php - How to create a pure CSS tooltip with HTML content for inline elements -


tl;dr - see adam's answer (accepted) or update #5 in question current solution. question shows journey getting solution in rather long explanatory way, describing pitfalls , limitations.

i creating module adds glossary term descriptions respective words used in text. works fine plain text descriptions. example, if there description onomasticon (another word thesaurus), following html

<p>an onomasticon not dinosaur.</p> 

gets converted

<p>an <dfn title="another word thesaurus">onomasticon</dfn> not dinosaur.</p>

since content (both article text , glossary term descriptions) come out of cms allows user use html, term's description may contain html, e.g. another word <strong>thesaurus</strong>. using above technique, starts messy:

<p>an <dfn title="another word <strong>thesaurus</strong>">onomasticon</dfn> not dinosaur.</p>

this default since tag attributes may not contain tags themselves. limitation can bypassed adding additional element inside dfn tag , adding css hide element initially:

dfn span {    display: none;  }  dfn:hover span {    display: block;    position: absolute;    top: 2.2em;    background: #ccc;  }
<p>an <dfn><span>another word <strong>thesaurus</strong></span>onomasticon</dfn> not dinosaur.</p>

but comes part, failing overcome. html tags <strong> inline elements not pose problem. however, if term's description contains block element, fails, e.g. if description contained in <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 <strong>thesaurus</strong></p></span>onomasticon</dfn> not dinosaur.</p>

what happens here? well, since block elements not allowed inside inline elements, outer inline element getting terminated , inner block element placed right after. thus, css selectors not working anymore, plus you'll end line breaks. of course, 1 might think of adding dfn span p { display: inline-block; } doesn't work either (neither inline), it's invalid html5.

although semantically incorrect, tried turn <dfn> <div class="dfn"> , inside <span> <div> since dfn, abbr , cite elements may contain phrasing context (just span). fails again due <div> not being allowed inside <p>, again unwanted line-break 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 <strong>thesaurus</strong></p></div>onomasticon</div> not dinosaur.</p>

that has been summary of journey far, trying reach holy grail of adding tooltip - containing html - inline element - such <dfn>, <abbr> or <cite> - using css only.

before javascript-based solutions, question whether or not missed option fulfils requirements listed below?

  • css only
  • tooltip must added <dfn>, <abbr> or <cite> inside paragraph
  • tooltip content may contain following html tags: div, p, h2, img, figure, ul, ol, li

update 1: since wrote module (php), of course able manipulate term's description. however, don't want strip <p> tags try keep intended markup.

update 2: found rather crude solution. let's description onomasticon html snippet like:

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

my module convert block elements spans appropriate class names, description becomes

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

this way, have inline elements shouldn't break phrasing context. adding more css style tooltip , make span.p behave p again, ends 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 <strong>thesaurus</strong></span>      <span class="p"><img src="http://i.imgur.com/g0bl4k7.png" /></span></span></span>onomasticon</dfn> not dinosaur.</p>

this best looking option far supporting limited html inline element's tooltips. however, it's not best option since requires hacky rewrite of html block elements.

update 3: christianf's answer had important clue how preserve html in glossary term definitions. if description not element inside dfn tag following sibling, still hide , show it, e.g. css selector dfn + div.dfn-tooltip. however, since glossary terms found in phrasing context, again break layout, since divs not permitted inside paragraph.

so need element, can both used in phrasing context and contain block elements. according beautiful html structure diagram, <button> tag 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 <strong>thesaurus</strong></p><p><img src="http://i.imgur.com/g0bl4k7.png" /></p></button> not dinosaur.</p>

this looks pretty promising. of course, there 2 major drawbacks: (1) button element @ place semantically incorrect , (2) tooltip doesn't stay open when hovering since it's not child of dfn tag anymore.

update 4: taking 1 little step further avoid second drawback move button element dfn tag, since context 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 <strong>thesaurus</strong></p><p><img src="http://i.imgur.com/g0bl4k7.png" /></p></button></dfn> not dinosaur.</p>

update 5 (final): adam's answer brought nice technique incorporate title attribute's original intention, putting together, ended 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 <strong>thesaurus</strong></p><p><img src="http://i.imgur.com/g0bl4k7.png" /></p></button></dfn> not dinosaur.</p>

by way, if interested, using in module called onomasticon, provides basic glossary functionality drupal 8.

note w3c says :

defining term: if dfn element has title attribute, exact value of attribute term being defined.

accordingly, can have simple solution put term being defined inside title attribute, , 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 <strong>thesaurus</strong></p>         <p><img src="http://i.imgur.com/g0bl4k7.png" /></p>        </button></dfn> not dinosaur.  </p>

i not find tag can replace here button element seems 1 working here.

so have add disabled attribute button element disable button behavior (focus) , set tabindex on dfn element enable arrow navigation.


Comments

Popular posts from this blog

asynchronous - C# WinSCP .NET assembly: How to upload multiple files asynchronously -

aws api gateway - SerializationException in posting new Records via Dynamodb Proxy Service in API -

asp.net - Problems sending emails from forum -