【问题标题】:Targeting text nodes with CSS使用 CSS 定位文本节点
【发布时间】:2016-11-21 19:31:04
【问题描述】:
我正在处理容器对象的 CSS。我大部分时间都在工作。具体来说,我正在查看测试用例 1、2 和 3。它们都有文本节点。有没有办法像对待任何子元素一样对待文本节点?
有没有办法调整 CSS 以使文本节点及其兄弟节点正常工作?除非有一个 CSS 选择器可以使用,它会选择一个 .container,如果有的话,只有在有一个文本节点的情况下,所以我可以 display: none 它(或者更好的东西,但仍然让开发人员知道事情不工作)?
这里也是Codepen。
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>code</code>
<br />
<quote>quote</quote>
<div id="0" class="container">
text
</div>
<div id="1" class="container">
<p>first child</p>
text
<code>last child</code>
</div>
<div id="2" class="container">
<p>first child</p>
text
</div>
<div id="3" class="container">
text
<p>last child</p>
</div>
<div id="4" class="container">
<p>first child</p>
<code>last child</code>
</div>
<div id="5" class="container">
<code>first child</code>
<p>last child</p>
</div>
<div id="6" class="container">
<code>first child</code>
<code>last child</code>
</div>
<div id="7" class="container">
<p>first child</p>
<p>last child</p>
</div>
<div id="8" class="container">
<code>only child</code>
</div>
<div id="9" class="container">
<p>first child</p>
<quote>middle child</quote>
<quote>middle child</quote>
<p>last child</p>
</div>
<div id="10" class="container">
<quote>
<div class="third">1</div>
<div class="third">2</div>
<div class="third">3</div>
</quote>
</div>
<div id="11" class="container">
<quote class="hidden">hidden child</quote>
<p>first child</p>
<p>last child</p>
</div>
<div id="12" class="container">
<p>first child</p>
<p>last child</p>
<quote class="hidden">hidden child</quote>
</div>
【问题讨论】:
标签:
html
css
css-selectors
【解决方案1】:
只有用 HTML 标记包裹的文本才能成为 CSS 的目标。
您没有被 HTML 标记明确包裹的文本在算法上被 匿名框包裹。这些框可以继承样式,但它们不能被 CSS 定位。
来自规范:
9.2.1.1 Anonymous block
boxes
匿名框的属性继承自封闭框
非匿名框。非继承属性有其初始值。
如果无法在匿名文本周围添加 HTML 标记,请考虑在容器上设置文本样式。对于可以定位的元素,您可以覆盖容器样式。当然,如果您希望文本具有display: none,则此方法将失败。
【解决方案2】:
在这种情况下,我很想将每个文本节点放在 <span> 中,这是经典的非语义短语元素。
(见:http://www.w3.org/TR/html-markup/span.html)
然后,您可以按照与设置 p 和 code 的样式类似的方式设置 span 的样式。
如果您选择这种方法,您有两个选择。您可以:
1) 将spans 直接写入标记:
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>
<code>last child</code>
</div>
<div id="container-2" class="container">
<p>first child</p>
<span>text</span>
</div>
<div id="container-3" class="container">
<span>text</span>
<p>last child</p>
</div>
或者,如果您不想在标记中包含spans,您可以
2) 在页面加载后动态添加span 元素:
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
<code>last child</code>
</div>
<div id="container-2" class="container">
<p>first child</p>
text
</div>
<div id="container-3" class="container">
text
<p>last child</p>
</div>