如何使用内联元素的HTML内容创建纯CSS工具提示 [英] How to create a pure CSS tooltip with HTML content for inline elements

查看:41
本文介绍了如何使用内联元素的HTML内容创建纯CSS工具提示的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

TL; DR -请参阅亚当的答案(已接受)或更新#5 当前解决方案的问题.我的问题显示了我的旅程以相当长的时间但可以解释的方式获得该解决方案,描述陷阱和局限性.

我正在创建一个模块,该模块将词汇表术语描述添加到文本中使用的各个单词.一切都可以使用纯文本描述正常运行.例如,如果有对onomasticon(同义词库的另一个词)的描述,则以下HTML

 < p>拟象虫不是恐龙. 

转换为

 < p>一个< dfn title =同义词库的另一个词"> onomasticon</dfn>不是恐龙.</p>  

由于内容(文章文字和词汇表术语描述)来自允许用户使用HTML的CMS,因此该术语的描述可能包含HTML,例如< strong>词库</strong> 的另一个词.使用上面的技术,这开始变得凌乱:

 < p>一个< dfn标题=< strong>同义词库</strong>的另一个词"> onomasticon</dfn>不是恐龙.</p>  

这是默认设置,因为标签属性可能不包含标签本身.可以通过在 dfn 标记内添加一个附加元素并添加一些CSS来初​​始隐藏该元素来绕过此限制:

  dfn span {显示:无;}dfn:hover span {显示:块;位置:绝对;顶部:2.2em;背景:#ccc;}  

 < p>一个< dfn>< span>< strong>词库</strong></span>的另一个词; onomasticon< dfn>不是恐龙.</p>  

但是现在来了,我无法克服.像< strong> 之类的HTML标签是不会造成问题的内联元素.但是,如果该术语的描述包含一个block元素,则此操作会失败,例如如果说明本身包含在< p> 标记中:

  dfn span {显示:无;}dfn:hover span {显示:块;位置:绝对;顶部:2.2em;背景:#ccc;}  

 < p>一个< dfn>< span> p</p>/跨度onomasticon</dfn>不是恐龙.</p>  

这是怎么回事?好吧,由于大多数内联元素内部不允许使用块元素,因此外部内联元素将终止,而内部块元素将紧随其后放置.因此,CSS选择器不再起作用,而且您最终将获得额外的换行符.当然,可能会想到添加 dfn span p {display:inline-block;} ,但这也不起作用( inline 也不起作用),它是无效的HTML5.

尽管从语义上讲是不正确的,但我还是尝试将< dfn> 转换为< div class ="dfn"> 和内部的&span>以及

div ,因为dfn,abbr和cite元素也可能仅包含短语上下文(与跨度一样).由于< div> 不允许在< p> 内而再次失败,再次添加了不必要的换行符:

  .dfn>div {显示:无;}.dfn:hover div {显示:inline-block;位置:绝对;顶部:2.2em;背景:#ccc;}  

 < p>一个< div class ="dfn">< div>< p>另一个表示< strong>的单词;同义词库/strong</p</div> onomasticon</div>不是恐龙.</p>  

到目前为止,这一直是我旅行的总结,它试图达到向内嵌元素(例如< dfn> < abbr> < cite> -仅使用CSS.

在我研究基于javascript的解决方案之前,我的问题是我是否错过了满足以下要求的选项?

  • 仅CSS
  • 工具提示必须添加到段落内的< dfn> < abbr> < cite>
  • 工具提示内容可能包含以下HTML标签:div,p,h2,img,fig,ul,ol,li

更新1:自从我编写了模块(PHP)之后,我当然能够操纵该术语的描述.但是,我不仅要剥离所有< p> 标记,还要尝试保留预期的标记.

更新2:我找到了一个比较粗糙的解决方案.假设 onomasticon 的描述是一些HTML代码段,例如:

 < p>< strong>词库</strong></p>的另一个词< p>< img src ="thesaurus.png"/></p> 

我的模块现在将使用适当的类名称将所有块元素转换为跨度,因此描述变为

 < span class ="p">< strong>词库</strong></span>的另一个词.< span class ="p">< img src ="thesaurus.png"/></span> 

这样,我有一些内联元素,它们不应破坏措辞上下文.添加更多CSS来设置工具提示的样式,并使 span.p 再次表现出与 p 相似的效果,

  dfn {显示:inline-block;职位:相对}dfn>跨度 {显示:无;}dfn:hover>跨度 {显示:块;位置:绝对;顶部:calc(1em + 5px);最大宽度:20em;背景:#ccc;填充:.5em;}dfn img {最大宽度:12em;}dfn>跨度span.p {显示:块;底边距:.5em;}  

 < p>一个< dfn>< span>< span class ="p">< strong>的另一个词; thesaurus</strong>/span>< span class ="p">< img src ="http://i.imgur.com/G0bl4k7.png"/>//span</span></span> onomasticon</dfn>不是恐龙.</p>  

到目前为止,这是我最好的选择,它支持内联元素的工具提示使用有限的HTML.但是,这可能不是最好的选择,因为它需要对HTML块元素进行巧妙的重写.

更新3: ChristianF的答案提供了一个非常重要的线索,说明如何在词汇表术语定义中保留HTML.如果描述不是dfn标签内的元素 ,而是后面的同级元素,我们仍然可以隐藏和显示它,例如使用CSS选择器 dfn + div.dfn-tooltip .但是,由于大多数词汇表术语都可以在措辞上下文中找到,这将再次破坏布局,因为在段落内不允许使用div.

因此,我们需要一个元素,该元素可以在短语上下文中使用,并且包含块元素.根据此美丽的HTML结构图< button> 标签应为只适合一个.

  p {显示:相对}dfn + .dfn-tooltip {显示:无;}dfn:hover + .dfn-tooltip {显示:块;位置:绝对;顶部:3em;最大宽度:20em;背景:#ccc;填充:.5em;边界:无;}.dfn-tooltip img {最大宽度:12em;}  

 < p>一个< dfn> onomasticon</dfn><按钮class ="dfn-tooltip">< p>;< strong>同义词库//strong></p>< p>< img src ="http://i.imgur.com/G0bl4k7.png"/></p></button>不是恐龙.</p>  

这看起来很有希望.当然,有两个主要缺点:(1)此位置的按钮元素在语义上不正确;(2)悬停时工具提示不会保持打开状态,因为它不再是dfn标记的子代.

更新4:,由于上下文相同,请采取进一步措施以避免第二个缺点,就是将按钮元素简单地移回dfn标记中.

  dfn {职位:相对显示:inline-block;}dfn>.dfn-tooltip {显示:无;}dfn:hover>.dfn-tooltip {显示:块;位置:绝对;顶部:calc(1em + 5px);最大宽度:20em;背景:#ccc;填充:.5em;边界:无;}.dfn-tooltip img {最大宽度:12em;}  

 < p>一个< dfn> onomasticon< button class ="dfn-tooltip">< p><; strong>同义词库//strong>/p</dfn>不是恐龙.</p>  

更新5(最终)::亚当的答案提出了一些很好的技术,可以合并标题属性的初衷,将所有内容放在一起,这就是我最终得到的结果.

  dfn {职位:相对显示:inline-block;光标:帮助;}dfn:之前{内容:attr(title);}dfn>.dfn-tooltip {显示:无;}dfn:hover>.dfn-tooltip {显示:块;位置:绝对;顶部:calc(1em + 5px);最大宽度:20em;背景:#ccc;填充:.5em;边界:无;光标:帮助;}.dfn-tooltip img {最大宽度:12em;}  

 < p>< dfn title ="onomasticon"><按钮已禁用class ="dfn-tooltip"><; p>< strong>词库</strong></p>< p>< img src ="http://i.imgur.com/G0bl4k7.png"/</p</button>/dfn>不是恐龙.</p>  

如果有人有兴趣,我会在名为 Onomasticon ,它为Drupal 8提供了基本的词汇表功能.

请注意,W3C表示:

定义术语:如果dfn元素具有标题属性,则该属性的确切值就是所定义的术语.

因此,您可以有一个简单的解决方案,将要定义的术语放在 title 属性中,并将定义放在

内部

  dfn :: before {content:attr(title); padding:0 0 1em;}dfn按钮{显示:无;位置:绝对}dfn:悬停按钮,dfn:焦点按钮{display:block;}  

 < p> An< dfn title ="onomasticon" tabindex ="0"><按钮已禁用>< p>< strong>词库</strong></p>的另一个词是< p>< img src ="http://i.imgur.com/G0bl4k7.png"/></p></button></dfn>不是恐龙.</p>  

我找不到任何可以代替 button 元素的标签,在这里似乎是唯一的标签.

因此,我们必须将 disabled 属性添加到 button 元素以禁用其 button 行为(焦点)并设置 dfn 元素上的tabindex 启用箭头导航.

TL;DR - See Adam's answer (accepted) or Update #5 in my question for the current solution. My question shows my journey getting to that solution in a rather long but explanatory way, describing pitfalls and limitations.

I am creating a module that adds glossary term descriptions to the respective words used in a text. Everything works fine with plain text descriptions. For example, if there is a description for onomasticon (Another word for thesaurus), the following HTML

<p>An onomasticon is not a dinosaur.</p>

gets converted to

<p>An <dfn title="Another word for thesaurus">onomasticon</dfn> is not a dinosaur.</p>

Since the content (both article text and glossary term descriptions) come out of a CMS which allows the user to use HTML, the term's description may contain HTML, e.g. Another word for <strong>thesaurus</strong>. Using the above technique, this starts to get messy:

<p>An <dfn title="Another word for <strong>thesaurus</strong>">onomasticon</dfn> is not a dinosaur.</p>

This is by default since tag attributes may not contain tags themselves. This limitation can be bypassed by adding an additional element inside the dfn tag and adding some CSS to hide the element initially:

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>

But now comes the part, I am failing to overcome. HTML tags like <strong> are inline elements which do not pose a problem. However, if the term's description contains a block element, this fails, e.g. if the description itself is contained in a <p> tag:

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>

What happens here? Well, since block elements are not allowed inside most inline elements, the outer inline element is getting terminated and the inner block element is placed right after. Thus, the CSS selectors are not working anymore, plus you'll end up with extra line breaks. Of course, one might think of adding something like dfn span p { display: inline-block; } but this doesn't work either (neither does inline), it's invalid HTML5.

Although semantically incorrect, I tried to turn <dfn> into <div class="dfn"> and the inside <span> to a <div> as well since dfn, abbr and cite elements may only contain phrasing context as well (just as span). This fails again due to <div> not being allowed inside <p>, again an unwanted line-break is added:

.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>

That has been the summary of my journey so far, trying to reach the holy grail of adding a tooltip - containing HTML - to an inline element - such as <dfn>, <abbr> or <cite> - using CSS only.

Before I now look into javascript-based solutions, my question is whether or not I missed an option which fulfils my requirements as listed below?

  • CSS only
  • tooltip must be added to <dfn>, <abbr> or <cite> inside a paragraph
  • tooltip content may contain the following HTML tags: div, p, h2, img, figure, ul, ol, li

Update 1: Since I wrote the module (PHP), I am of course able to manipulate the term's description. However, I don't just want to strip all <p> tags but try to keep the intended markup.

Update 2: I found a rather crude solution. Let's say the description for onomasticon is some HTML snippet like:

<p>Another word for <strong>thesaurus</strong></p>
<p><img src="thesaurus.png" /></p>

My module will now convert all block elements to spans with appropriate class names, so the description becomes

<span class="p">Another word for <strong>thesaurus</strong></span>
<span class="p"><img src="thesaurus.png" /></span>

This way, I have inline elements which shouldn't break the phrasing context. Adding some more CSS to style the tooltip and make span.p behave somewhat like a p again, it all ends up to this.

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>

This is my best looking option so far supporting limited HTML for inline element's tooltips. However, it's probably not the best option since it requires the hacky rewrite of HTML block elements.

Update 3: ChristianF's answer had a very important clue how to preserve HTML in glossary term definitions. If the description is not an element inside the dfn tag but a following sibling, we could still hide and show it, e.g. with the CSS selector dfn + div.dfn-tooltip. However, since most glossary terms will be found in a phrasing context, this will again break the layout, since divs are not permitted inside a paragraph.

So we would need an element, that can be both used in a phrasing context and contain block elements. According to this beautiful HTML structure diagram, the <button> tag would be the only suitable one.

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>

This looks pretty promising. Of course, there are two major drawbacks: (1) a button element at this place is semantically incorrect and (2) the tooltip doesn't stay open when hovering itself since it's not a child of the dfn tag anymore.

Update 4: Taking one little step further to avoid the second drawback is to simply move the button element back into the dfn tag, since the context is the same.

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's answer brought up some nice technique to incorporate the title attribute's original intention, putting everything together, this is what I ended up with.

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>

By the way, if anyone is interested, I am using this in a module called Onomasticon, which provides a basic glossary functionality for Drupal 8.

解决方案

Note that W3C says :

Defining term: If the dfn element has a title attribute, then the exact value of that attribute is the term being defined.

Accordingly, you can have a simple solution where you put the term being defined inside the title attribute, and the definition inside

dfn::before {content: attr(title);padding: 0 0 1em;}      
dfn button {display: none; position: absolute}
dfn:hover button, dfn:focus button {display: block;}

<p>An
     <dfn title="onomasticon" tabindex="0"><button disabled>
       <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>

I do not find any tag that can replace here the button element which seems to be the only one working here.

So we have to add the disabled attribute to the button element to disable its button behavior (focus) and set the tabindex on the dfn element to enable arrow navigation.

这篇关于如何使用内联元素的HTML内容创建纯CSS工具提示的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆