Targeting text nodes with CSS

html css css3 css-selectors

658 просмотра

2 ответа

10041 Репутация автора

I'm working on the CSS for a container object. I have it mostly working. Specifically, I'm looking at test case 1, 2 and 3. They all have text nodes. Is there a way to treat a text node just like any child element?

Is there any way to tweak the CSS to get text nodes and its siblings to work nicely? Barring that is there a CSS selector to use that will select a .container if any only if there is a text node so I can display: none it (or something nicer but still to let the dev know things aren't working)?

Here is a Codepen as well.

code,
p,
quote {
  display: block;
  position: relative;
  margin: 0;
  padding: 1em;
  border: 1px solid black;
  box-sizing: border-box;
}
code {
  background-color: #ccc;
}
p {
  background-color: #0df;
}
quote {
  background-color: #fd0;
}
quote::after {
  display: table;
  clear: both;
  content: "";
}
.hidden {
  display: none;
}
.third {
  height: 100%;
  width: 33%;
  float: left;
  border: 1px solid black;
}
.container {
  display: block;
  position: relative;
  margin-right: 0;
  margin-left: 0;
  margin-top: 1.5em;
  margin-bottom: 1.5em;
  padding: 0.5rem;
  border: 1px solid black;
  box-sizing: border-box;
  border-radius: 10px;
  box-shadow: none;
}
.container >:first-child {
  border-top-left-radius: 10px;
  border-top-right-radius: 10px;
  border-bottom-left-radius: 0;
  border-bottom-right-radius: 0;
  border-width: 0;
  margin-top: -0.5rem;
  margin-bottom: -0.5rem;
  margin-left: -0.5rem;
  margin-right: -0.5rem;
}
.container >:last-child {
  border-top-left-radius: 0;
  border-top-right-radius: 0;
  border-bottom-left-radius: 10px;
  border-bottom-right-radius: 10px;
  border-bottom-width: 0;
  border-left-width: 0;
  border-right-width: 0;
  margin-top: 0.5rem;
  margin-bottom: -0.5rem;
  margin-left: -0.5rem;
  margin-right: -0.5rem;
}
.container >:not(:first-child):not(:last-child) {
  margin-left: -0.5rem;
  margin-right: -0.5rem;
  margin-bottom: -0.5rem;
  border-right-width: 0;
  border-left-width: 0;
  border-bottom-width: 0;
}
.container >:only-child {
  border-radius: 10px;
  border-width: 0;
  margin-top: -0.5rem;
  margin-bottom: -0.5rem;
  margin-left: -0.5rem;
  margin-right: -0.5rem;
}
<p>p</p>
<br />
code

quote
text

first child

text last child

first child

text
text

last child

first child

last child
first child

last child

first child last child

first child

last child

only child

first child

middle child middle child

last child

1
2
3

first child

last child

first child

last child

Автор: Justin808 Источник Размещён: 19.07.2016 04:10

Ответы (2)


3 плюса

183034 Репутация автора

Only text that is wrapped in HTML tags can be targeted by CSS.

Your text that is not explicitly wrapped by HTML tags is algorithmically wrapped by anonymous boxes. These boxes may inherit styles, but they cannot be targeted by CSS.

From the spec:

9.2.1.1 Anonymous block boxes

The properties of anonymous boxes are inherited from the enclosing non-anonymous box. Non-inherited properties have their initial value.

If adding HTML tags around your anonymous text is not an option, consider setting the text styles on the container. For the elements that can be targeted, you can then override the container styles. Of course, this method will fall flat if you want the text to have display: none.

Автор: Michael_B Размещён: 19.07.2016 04:17

0 плюса

14244 Репутация автора

In this case, I'd be tempted to place each text node inside a <span> which is the classic, non-semantic phrasing element.

(See: http://www.w3.org/TR/html-markup/span.html)

You can then style the span in a similar manner to the way you have styled the p and the code.

If you choose this approach, you have two choices. You can either:

1) Write the spans directly into the markup:

code, p, quote, span {
  display: block;
  position: relative;
  margin: 0;
  padding: 1em;
  border: 1px solid black;
  box-sizing: border-box;
}

p {background-color: #0df;}
code {background-color: #ccc;}
span {background-color: #fff;}


.container {
  display: block;
  position: relative;
  margin-right: 0;
  margin-left: 0;
  margin-top: 1.5em;
  margin-bottom: 1.5em;
  padding: 0.5rem;
  border: 1px solid black;
  box-sizing: border-box;
  border-radius: 10px;
  box-shadow: none;
}

.container :first-child {
  border-top-left-radius: 10px;
  border-top-right-radius: 10px;
  border-bottom-left-radius: 0;
  border-bottom-right-radius: 0;
  border-width: 0;
  margin-top: -0.5rem;
  margin-bottom: -0.5rem;
  margin-left: -0.5rem;
  margin-right: -0.5rem;
}
.container >:last-child {
  border-top-left-radius: 0;
  border-top-right-radius: 0;
  border-bottom-left-radius: 10px;
  border-bottom-right-radius: 10px;
  border-bottom-width: 0;
  border-left-width: 0;
  border-right-width: 0;
  margin-top: 0.5rem;
  margin-bottom: -0.5rem;
  margin-left: -0.5rem;
  margin-right: -0.5rem;
}
.container >:not(:first-child):not(:last-child) {
  margin-left: -0.5rem;
  margin-right: -0.5rem;
  margin-bottom: -0.5rem;
  border-right-width: 0;
  border-left-width: 0;
  border-bottom-width: 0;
}
.container >:only-child {
  border-radius: 10px;
  border-width: 0;
  margin-top: -0.5rem;
  margin-bottom: -0.5rem;
  margin-left: -0.5rem;
  margin-right: -0.5rem;
}
<div id="container-1" class="container">
<p>first child</p>
<span>text</span>
last child

first child

text
text

last child

Or, if you prefer not to have spans included in your markup, you can

2) Add the span elements dynamically, after the page loads:

var containers = document.getElementsByClassName('container');

for (var i = 0; i < containers.length; i++) {
    for (var j = 0; j < containers[i].childNodes.length; j++) {
        if (containers[i].childNodes[j].nodeName !== '#text') {continue;} /* skips all nodes which aren't text nodes */
        if (/^[\s\n]*$/.test(containers[i].childNodes[j].textContent)) {continue;} /* skips all text nodes containing only whitespace and newlines */

        var text = containers[i].childNodes[j];
        var span = document.createElement('span');
        span.appendChild(text);
        span.textContent = span.textContent.trim();
        containers[i].insertBefore(span,containers[i].childNodes[j]);
    }
}
code, p, quote, span {
  display: block;
  position: relative;
  margin: 0;
  padding: 1em;
  border: 1px solid black;
  box-sizing: border-box;
}

p {background-color: #0df;}
code {background-color: #ccc;}
span {background-color: #fff;}


.container {
  display: block;
  position: relative;
  margin-right: 0;
  margin-left: 0;
  margin-top: 1.5em;
  margin-bottom: 1.5em;
  padding: 0.5rem;
  border: 1px solid black;
  box-sizing: border-box;
  border-radius: 10px;
  box-shadow: none;
}

.container :first-child {
  border-top-left-radius: 10px;
  border-top-right-radius: 10px;
  border-bottom-left-radius: 0;
  border-bottom-right-radius: 0;
  border-width: 0;
  margin-top: -0.5rem;
  margin-bottom: -0.5rem;
  margin-left: -0.5rem;
  margin-right: -0.5rem;
}
.container >:last-child {
  border-top-left-radius: 0;
  border-top-right-radius: 0;
  border-bottom-left-radius: 10px;
  border-bottom-right-radius: 10px;
  border-bottom-width: 0;
  border-left-width: 0;
  border-right-width: 0;
  margin-top: 0.5rem;
  margin-bottom: -0.5rem;
  margin-left: -0.5rem;
  margin-right: -0.5rem;
}
.container >:not(:first-child):not(:last-child) {
  margin-left: -0.5rem;
  margin-right: -0.5rem;
  margin-bottom: -0.5rem;
  border-right-width: 0;
  border-left-width: 0;
  border-bottom-width: 0;
}
.container >:only-child {
  border-radius: 10px;
  border-width: 0;
  margin-top: -0.5rem;
  margin-bottom: -0.5rem;
  margin-left: -0.5rem;
  margin-right: -0.5rem;
}
<div id="container-1" class="container">
<p>first child</p>
text
last child

first child

text
text

last child

Автор: Rounin says Je suis Monica Размещён: 30.07.2016 05:56
Вопросы из категории :
32x32