【发布时间】:2017-03-24 16:24:16
【问题描述】:
TL;DR - 请参阅 Adam 的回答(已接受)或我的 Update #5 当前解决方案的问题。我的问题显示了我的旅程 以相当长但解释性的方式获得该解决方案, 描述陷阱和限制。
我正在创建一个模块,用于将词汇表术语描述添加到文本中使用的各个单词中。纯文本描述一切正常。例如,如果有对 onomasicon(同义词库的另一个词)的描述,则以下 HTML
<p>An onomasticon is not a dinosaur.</p>
转换成
<p>An <dfn title="Another word for thesaurus">onomasticon</dfn> is not a dinosaur.</p>
由于内容(文章文本和词汇表术语描述)来自允许用户使用 HTML 的 CMS,因此术语的描述可能包含 HTML,例如Another word for <strong>thesaurus</strong>。使用上述技术,这开始变得混乱:
<p>An <dfn title="Another word for <strong>thesaurus</strong>">onomasticon</dfn> is not a dinosaur.</p>
这是默认设置,因为标签属性可能不包含标签本身。这个限制可以通过在dfn标签内添加一个额外的元素并添加一些CSS来隐藏元素来绕过:
dfn span {
display: none;
}
dfn:hover span {
display: block;
position: absolute;
top: 2.2em;
background: #ccc;
}
<p>An <dfn><span>Another word for <strong>thesaurus</strong></span>onomasticon</dfn> is not a dinosaur.</p>
但现在到了,我没能克服。像<strong> 这样的HTML 标签是不会造成问题的内联元素。但是,如果术语的描述包含块元素,则会失败,例如如果描述本身包含在<p> 标签中:
dfn span {
display: none;
}
dfn:hover span {
display: block;
position: absolute;
top: 2.2em;
background: #ccc;
}
<p>An <dfn><span><p>Another word for <strong>thesaurus</strong></p></span>onomasticon</dfn> is not a dinosaur.</p>
这里发生了什么?好吧,由于大多数内联元素中不允许使用块元素,因此外部内联元素将被终止,而内部块元素则紧随其后。因此,CSS 选择器不再起作用,而且您最终会遇到额外的换行符。当然,有人可能会考虑添加类似dfn span p { display: inline-block; } 的内容,但这也不起作用(inline 也不行),它是无效的 HTML5。
虽然语义不正确,但我尝试将 <dfn> 转换为 <div class="dfn"> 并将内部 <span> 转换为 <div> 以及因为 dfn、abbr 和 cite 元素也可能只包含短语上下文(就像 span) .由于 <div> 不允许在 <p> 内,这再次失败,再次添加了不需要的换行符:
.dfn > div {
display: none;
}
.dfn:hover div {
display: inline-block;
position: absolute;
top: 2.2em;
background: #ccc;
}
<p>An <div class="dfn"><div><p>Another word for <strong>thesaurus</strong></p></div>onomasticon</div> is not a dinosaur.</p>
这是我迄今为止的旅程总结,试图达到将工具提示(包含 HTML)添加到内联元素(例如 <dfn>、<abbr> 或 <cite>)的圣杯 - 仅使用 CSS .
在我现在研究基于 javascript 的解决方案之前,我的问题是我是否错过了满足我下面列出的要求的选项?
- 仅 CSS
- 工具提示必须添加到段落内的
<dfn>、<abbr>或<cite> - 工具提示内容可能包含以下 HTML 标签:div、p、h2、img、figure、ul、ol、li
更新 1: 因为我编写了模块 (PHP),所以我当然能够操纵术语的描述。但是,我不只是想剥离所有 <p> 标记,而是尝试保留预期的标记。
更新 2: 我找到了一个相当粗略的解决方案。假设onomasticon 的描述是一些 HTML sn-p 之类的:
<p>Another word for <strong>thesaurus</strong></p>
<p><img src="thesaurus.png" /></p>
我的模块现在会将所有块元素转换为具有适当类名的 span,因此描述变为
<span class="p">Another word for <strong>thesaurus</strong></span>
<span class="p"><img src="thesaurus.png" /></span>
这样,我就有了不应破坏短语上下文的内联元素。添加更多的 CSS 来设置工具提示的样式并让 span.p 再次表现得有点像 p,这一切都结束了。
dfn {
display: inline-block;
position: relative;
}
dfn > span {
display: none;
}
dfn:hover > span {
display: block;
position: absolute;
top: calc(1em + 5px);
max-width: 20em;
background: #ccc;
padding: .5em;
}
dfn img {
max-width: 12em;
}
dfn > span span.p {
display: block;
margin-bottom: .5em;
}
<p>An <dfn><span><span class="p">Another word for <strong>thesaurus</strong></span>
<span class="p"><img src="http://i.imgur.com/G0bl4k7.png" /></span></span></span>onomasticon</dfn> is not a dinosaur.</p>
这是迄今为止我最好看的选项,它支持有限的 HTML 用于内联元素的工具提示。但是,它可能不是最好的选择,因为它需要对 HTML 块元素进行 hacky 重写。
更新 3: ChristianF 的回答有一个非常重要的线索,即如何在词汇表术语定义中保留 HTML。如果描述不是 dfn 标签 inside 的元素,而是后面的兄弟,我们仍然可以隐藏和显示它,例如使用 CSS 选择器 dfn + div.dfn-tooltip。但是,由于大多数词汇表术语会在短语上下文中找到,这将再次破坏布局,因为段落中不允许使用 div。
所以我们需要一个元素,既可以在短语上下文中使用,又可以包含块元素。根据这个beautiful HTML structure diagram,<button> 标签将是唯一合适的标签。
p {
display: relative;
}
dfn + .dfn-tooltip {
display: none;
}
dfn:hover + .dfn-tooltip {
display: block;
position: absolute;
top: 3em;
max-width: 20em;
background: #ccc;
padding: .5em;
border: none;
}
.dfn-tooltip img {
max-width: 12em;
}
<p>An <dfn>onomasticon</dfn><button class="dfn-tooltip"><p>Another word for <strong>thesaurus</strong></p><p><img src="http://i.imgur.com/G0bl4k7.png" /></p></button> is not a dinosaur.</p>
这看起来很有希望。当然,有两个主要缺点:(1)这个地方的按钮元素在语义上是不正确的;(2)工具提示在悬停时不会保持打开状态,因为它不再是 dfn 标签的子元素。
更新 4: 进一步避免第二个缺点是只需将按钮元素移回 dfn 标记,因为上下文是相同的。
dfn {
position: relative;
display: inline-block;
}
dfn > .dfn-tooltip {
display: none;
}
dfn:hover > .dfn-tooltip {
display: block;
position: absolute;
top: calc(1em + 5px);
max-width: 20em;
background: #ccc;
padding: .5em;
border: none;
}
.dfn-tooltip img {
max-width: 12em;
}
<p>An <dfn>onomasticon<button class="dfn-tooltip"><p>Another word for <strong>thesaurus</strong></p><p><img src="http://i.imgur.com/G0bl4k7.png" /></p></button></dfn> is not a dinosaur.</p>
Update 5(final):Adam 的回答提出了一些很好的技巧来结合 title 属性的初衷,把所有东西放在一起,这就是我最终的结果。
dfn {
position: relative;
display: inline-block;
cursor: help;
}
dfn:before {
content: attr(title);
}
dfn > .dfn-tooltip {
display: none;
}
dfn:hover > .dfn-tooltip {
display: block;
position: absolute;
top: calc(1em + 5px);
max-width: 20em;
background: #ccc;
padding: .5em;
border: none;
cursor: help;
}
.dfn-tooltip img {
max-width: 12em;
}
<p>An <dfn title="onomasticon"><button disabled class="dfn-tooltip"><p>Another word for <strong>thesaurus</strong></p><p><img src="http://i.imgur.com/G0bl4k7.png" /></p></button></dfn> is not a dinosaur.</p>
顺便说一句,如果有人感兴趣,我在一个名为 Onomasticon 的模块中使用它,它为 Drupal 8 提供了基本的词汇表功能。
【问题讨论】:
-
如果您的 /requirements/ 要求您能够在段落中添加段落,那么您就处于障碍状态。这些要求是从哪里来的?您愿意改变这些要求吗?
-
@andi 这是一个基于 Drupal 的网站的模块。目前,客户可以在术语描述中仅使用纯文本,但在发布后,他们寻求一种解决方案,在该解决方案中,他们也能够在描述中添加段落和可能的图像。这本身没有问题,因为 Drupal 提供了一个富文本编辑器来做到这一点。我正在努力将富文本内容放入工具提示中。由于 Drupal 本身依赖 jQuery,我可以使用 jQuery,但我想避免在我的模块中添加另一个 JS 库(依赖项)。
-
是否有任何硬性要求阻止您将
p标签替换为一个(或两个)br标签?诚然,这在语义上不是最干净的解决方案,但仍然完全合法。 -
基本上,这就是我现在所做的,虽然有点不同(参见更新 2)。我将
<p>替换为<span class="p">并添加以下 CSS:span.p {display: block; margin-bottom: .5em;}