vuepress-plugin-live icon indicating copy to clipboard operation
vuepress-plugin-live copied to clipboard

Styles only applied to root element

Open AustinGil opened this issue 4 years ago • 5 comments

When creating a live Vue component with styles, it looks like this plugin generates the markup and gives the root component a unique data attribute. Styles are then generated for this component based on that attribute as follows:

Original Vue component:

<template>
  <div class="parent">
    <div class="child"></div>
  </div>
</template>
<style>
.parent {
  background: red;
}
.child {
  background: blue;
}
</style>

Output HTML

<div class="parent" data-v-3ebe6f67>
  <div class="child"></div>
</div>

Output styles

.parent[data-v-3ebe6f67] {
  background: red;
}
.child[data-v-3ebe6f67] {
  background: blue;
}

A data attribute is added to the root element in the example, and the same data attribute is added to the style block rules.

This works fine for the root element, but any nested element with the child class does not properly get styled because the added data attribute interferes.

There two solutions I can think of would be to remove the data attribute or add it to every nested HTML element.

AustinGil avatar Nov 17 '19 01:11 AustinGil

The solution I advocate for is to add the data attribute to every tag in there. This will avoid style bleeding.

elevatebart avatar Nov 19 '19 14:11 elevatebart

in the demo of vue-live the data attributes seem to be added to the right objects. I might need a reproduction repo. Would you mind creating one please ?

elevatebart avatar Nov 19 '19 14:11 elevatebart

I see what the issue was that I was dealing with. The bug is not exactly how I reported it, but something similar.

For reference, the project I'm working on is here: https://vuetensils.stegosource.com/components/valert.html

In this example, I have a dismissible alert component (VAlert) that is used like this:

<template>
  <VAlert class="info" dismissible>
    Did you know that giraffes are afraid of heights?
  </VAlert>
</template>

The output HTML is:

<div data-v-7753c69c="" role="alert" class="info vts-alert">
  Did you know that giraffes are afraid of heights?
  <button aria-label="Dismiss this alert" class="vts-alert__dismiss">×</button>
</div>

Now, if I add a style block to my Vue component like so:

<style>
.vts-alert.info {
  display: flex;
  align-items: center;
  justify-content: space-between;
  border: 1px solid currentColor;
  border-radius: 4px;
  padding: 10px;
  color: #009;
  background: #dff;
}

.vts-alert.info .vts-alert__dismiss {
  border: 0;
  font: inherit;
  background: transparent;
}
</style>

I would expect my alert to be blue, and my button to have a transparent background. However, the output CSS is:

.vts-alert.info[data-v-7753c69c] {
  display: flex;
  align-items: center;
  justify-content: space-between;
  border: 1px solid currentColor;
  border-radius: 4px;
  padding: 10px;
  color: #009;
  background: #dff;
}

.vts-alert.info[data-v-7753c69c] .vts-alert__dismiss[data-v-7753c69c] {
  border: 0;
  font: inherit;
  background: transparent;
}

So the output CSS does work as you have explained above. However, what I would like to be able to do, and cannot currently do, is apply styles to the elements that come from a Vue component. In other words, if I render a custom Vue component (VAlert) inside the vue-live editor, I would like to be able to apply styles to the nested markup of that custom component. Not just the root element.

I hope that makes sense.

I also recognize the complexity of this task, taking in consideration avoiding style leaks. But I'm finding that to satisfy my needs, I have to wrap all my examples in a div with a unique class and add my custom styles somewhere else.

Perhaps this use-case only applies to me though since I'm developing a library of intentionally unstyled components that the user is expected to style over.

AustinGil avatar Nov 19 '19 17:11 AustinGil

Have you tried using deep selectors?

I have implemented them in the compiler in 3.23.0 which might not be up to date on vue-live yet.

I would be open to peer prog a little to see what is best.

elevatebart avatar Nov 19 '19 17:11 elevatebart

I did not try deep selectors, but in testing it just now, the output CSS is

.vts-alert.info[data-v-b4abcdb2] {
  display: flex;
  align-items: center;
  justify-content: space-between;
  border: 1px solid currentColor;
  border-radius: 4px;
  padding: 10px;
  color: #009;
  background: #dff;
}

.vts-alert.info[data-v-b4abcdb2] >>>[data-v-b4abcdb2] .vts-alert__dismiss[data-v-b4abcdb2] {
  border: 0;
  font: inherit;
  background: transparent;
}

Haha. So not quite right.

I'm down to pair, but I also want to be respectful of your time and I feel like I am probably the only person dealing with this, and there is a solution in putting my CSS in an external file. If you do want to go forward with it, how would we make that work?

AustinGil avatar Nov 19 '19 17:11 AustinGil