Tag: HTML

How to Add Text in Borders Using Basic HTML Elements

Some HTML elements come with preset designs, like the inconveniently small squares of <input type="checkbox"> elements, the limited-color bars of <meter> elements, and the “something about them bothers me” arrows of the <details> elements. We can style them to match the modern aesthetics of our websites while making use of their functionalities. There are also many elements that rarely get used as both their default appearance and functionality are less needed in modern web designs.

One such HTML element is <fieldset>, along with its child element <legend>.

A <fieldset> element is traditionally used to group and access form controls. We can visually notice the grouping by the presence of a border around the grouped content on the screen. The caption for this group is given inside the <legend> element that’s added as the first child of the <fieldset>.

This combination of <fieldset> and <legend> creates a unique ready-made “text in border” design where the caption is placed right where the border is and the line of the border doesn’t go through the text. The border line “breaks” when it encounters the beginning of the caption text and resumes after the text ends.

In this post, we’ll make use of the <fieldset> and <legend> combo to create a more modern border text design that’s quick and easy to code and update.

For the four borders, we need four <fieldset> elements, each containing a <legend> element inside. We add the text that will appear at the borders inside the <legend> elements.

<fieldset><legend>Wash Your Hands</legend></fieldset> <fieldset><legend>Stay Apart</legend></fieldset> <fieldset><legend>Wear A Mask</legend></fieldset> <fieldset><legend>Stay Home</legend></fieldset>

To begin, we stack the <fieldset> elements on top of each other in a grid cell and give them borders. You can stack them using any way you want — it doesn’t necessarily have to be a grid.

Only the top border of each <fieldset> element is kept visible while the remaining edges are transparent since the text of the <legend> element appears at the top border of the <fieldset> by default.

Also, we give all the <fieldset> elements a box-sizing property with a value of border-box so the width and height of the <fieldset> elements include their border and padding sizes too. Doing this later creates a leveled design, when we style the <legend> elements.

body {   display: grid;    margin: auto; /* to center */   margin-top: calc(50vh - 170px); /* to center */   width: 300px; height: 300px;  }  fieldset {   border: 10px solid transparent;    border-top-color: black;    box-sizing: border-box;    grid-area: 1 / 1; /* first row, first column */   padding: 20px;    width: inherit;  }

After this, we rotate the last three <fieldset> elements in order to use their top borders as the side and bottom borders of our design.

/* rotate to right */ fieldset:nth-of-type(2){ transform: rotate(90deg); } /* rotate to bottom */ fieldset:nth-of-type(3){ transform: rotate(180deg); } /* rotate to left */ fieldset:nth-of-type(4){ transform: rotate(-90deg); }

Next up is styling the <legend> elements. The key to create smooth border text using a <legend> element is to give it a zero (or small enough) line-height. If it has a large line height, that will displace the position of the border it’s in, pushing the border down. And when the border moves with the line height, we won’t be able to connect all the four sides of our design and will need to readjust the borders.

legend {   font: 15pt/0 'Averia Serif Libre';    margin: auto; /* to center */   padding: 0 4px;  }  fieldset:nth-of-type(3) > legend {    transform: rotate(180deg); }

I used the font shorthand property to give the values for the font-size, line-height and font-family properties of the <legend> elements.

The <legend> element that adds the text at the bottom border of our design, fieldset:nth-of-type(3)>legend, is upside-down because of its rotated <fieldset> parent element. Flip that <legend> element vertically to show its text right-side-up.

Add an image to the first <fieldset> element and you get something like this:

Lateral margins can move the text along the border. Left and right margins with auto values will center the text, as seen in the above Pen. Only the left margin with an auto value will flush the text to the right, and vice versa, for the right margin.

Bonus: After a brief geometrical detour, here’s an octagonal design I made using the same technique:


The post How to Add Text in Borders Using Basic HTML Elements appeared first on CSS-Tricks.

You can support CSS-Tricks by being an MVP Supporter.

CSS-Tricks

, , , , ,

A Complete State Machine Made With HTML Checkboxes and CSS

State machines are typically expressed on the web in JavaScript and often through the popular XState library. But the concept of a state machine is adaptable to just about any language, including, amazingly, HTML and CSS. In this article, we’re going to do exactly that. I recently built a website that included a “no client JavaScript” constraint and I needed one particular unique interactive feature.

The key to all this is using <form> and <input type="radio"> elements to hold a state. That state is toggled or reset with another radio <input> or reset <button> that can be anywhere on the page because it is connected to the same <form> tag. I call this combination a radio reset controller, and it is explained in more detail at the end of the article. You can add more complex state with additional form/input pairs.

It’s a little bit like the Checkbox Hack in that, ultimately, the :checked selector in CSS will be doing the UI work, but this is logically more advanced. I end up using a templating language (Nunjucks) in this article to keep it manageable and configurable.

Traffic light state machine

Any state machine explanation must include the obligatory traffic light example. Below is a working traffic light that uses a state machine in HTML and CSS. Clicking “Next” advances the state. The code in this Pen is post processed from the state machine template to fit in a Pen. We’ll get into the code in a more readable fashion later on.

Hiding/Showing table information

Traffic lights aren’t the most practical every-day UI. How about a <table> instead?

There are two states (A and B) that are changed from two different places in the design that affect changes all over the UI. This is possible because the empty <form> elements and <input> elements that hold state are at the very top of the markup and thus their state can be deduced with general sibling selectors and the rest of the UI can be reached with descendent selectors. There is a loose coupling of UI and markup here, meaning we can change the state of almost anything on the page from anywhere on the page.

General four-state component

Diagram of a generic four-state finite state machine

The goal is a general purpose component to control the desired state of the page. “Page state” here refers to the desired state of the page and “machine state” refers to the internal state of the controller itself. The diagram above shows this generic state machine with four states(A, B, C and D). The full controller state machine for this is shown below. It is built using three of the radio reset controller bits. Adding three of these together forms a state machine that has eight internal machine states (three independent radio buttons that are either on or off).

Diagram of the controller’s internal states

The “machine states” are written as a combination of the three radio buttons (i.e. M001 or M101). To transition from the initial M111 to M011, the radio button for that bit is unset by clicking on another radio <input> in the same group. To transition back, the reset <button> for the <form> attached to that bit is clicked which restores the default checked state. Although this machine has eight total states, only certain transitions are possible. For instance, there is no way to go directly from M111 to M100 because it requires two bits to be flipped. But if we fold these eight states into four states so that each page state shares two machine states (i.e. A shares states M111 and M000) then there is a single transition from any page state to any other page state.

Reusable four-state component

For reusability, the component is built with Nunjucks template macros. This allows it to be dropped into any page to add a state machine with the desired valid states and transitions. There are four required sub-components:

  • Controller
  • CSS logic
  • Transition controls
  • State classes

Controller

The controller is built with three empty form tags and three radio buttons. Each of the radio buttons checked attribute is checked by default. Each button is connected to one of the forms and they are independent of each other with their own radio group name. These inputs are hidden with display: none because they are are not directly changed or seen. The states of these three inputs comprise the machine state and this controller is placed at the top of the page.

{% macro FSM4S_controller()%}   <form id="rrc-form-Bx00"></form>   <form id="rrc-form-B0x0"></form>   <form id="rrc-form-B00x"></form>   <input data-rrc="Bx00" form="rrc-form-Bx00" style="display:none" type="radio" name="rrc-Bx00" checked="checked" />   <input data-rrc="B0x0" form="rrc-form-B0x0" style="display:none" type="radio" name="rrc-B0x0" checked="checked" />   <input data-rrc="B00x" form="rrc-form-B00x" style="display:none" type="radio" name="rrc-B00x" checked="checked" /> {% endmacro %}

CSS logic

The logic that connects the controller above to the state of the page is written in CSS. The Checkbox Hack uses a similar technique to control sibling or descendant elements with a checkbox. The difference here is that the button controlling the state is not tightly coupled to the element it is selecting. The logic below selects based on the “checked” state of each of the three controller radio buttons and any descendant element with class .M000. This state machine hides any element with the .M000 class by setting display: none !important. The !important isn’t a vital part of the logic here and could be removed; it just prioritizes the hiding from being overridden by other CSS.

{%macro FSM4S_css()%} <style>   /* Hide M000 (A1) */   input[data-rrc="Bx00"]:not(:checked)~input[data-rrc="B0x0"]:not(:checked)~input[data-rrc="B00x"]:not(:checked)~* .M000  {     display: none !important;   }    /* one section for each of 8 Machine States */  </style> {%endmacro%}

Transition control

Changing the state of the page requires a click or keystroke from the user. To change a single bit of the machine state, the user clicks on a radio button that is connected to the same form and radio group of one of the bits in the controller. To reset it, the user clicks on a reset button for the form connected to that same radio button. The radio button or the reset button is only shown depending on which state they are in. A transition macro for any valid transition is added to the HTML. There can be multiple transitions placed anywhere on the page. All transitions for states currently inactive will be hidden.

{%macro AtoB(text="B",class="", classBtn="",classLbl="",classInp="")%}   <label class=" {{class}} {{classLbl}} {{showM111_A()}} "><input class=" {{classInp}} " form="rrc-form-Bx00" type="radio" name="rrc-Bx00" />{{text}}</label>   <button class=" {{class}} {{classBtn}} {{showM000_A1()}} " type="reset" form="rrc-form-Bx00">{{text}}</button> {%endmacro%} 

State class

The three components above are sufficient. Any element that depends on state should have the classes applied to hide it during other states. This gets messy. The following macros are used to simplify that process. If a given element should be shown only in state A, the {{showA()}} macro adds the states to hide.

{%macro showA() %}   M001 M010 M100 M101 M110 M011 {%endmacro%} 

Putting it all together

The markup for the traffic light example is shown below. The template macros are imported in the first line of the file. The CSS logic is added to the head and the controller is at the top of the body. The state classes are on each of the lights of the .traffic-light element. The lit signal has a {{showA()}} macro while the “off” version of signal has the machine states for the .M000 and .M111 classes to hide it in the A state. The state transition button is at the bottom of the page.

{% import "rrc.njk" as rrc %} <!DOCTYPE html> <html lang="en"> <head>   <meta charset="UTF-8" />   <title>Traffic Light State Machine Example</title>   <link rel="stylesheet" href="styles/index.processed.css">   {{rrc.FSM4S_css()}} </head> <body>   {{rrc.FSM4S_controller()}}   <div>     <div class="traffic-light">       <div class="{{rrc.showA()}} light red-light on"></div>       <div class="M111 M000 light red-light off"></div>       <div class="{{rrc.showB()}} light yellow-light on"></div>       <div class="M100 M011 light yellow-light off"></div>       <div class="{{rrc.showC()}} light green-light on"></div>       <div class="M010 M101 light green-light off"></div>     </div>     <div>       <div class="next-state">         {{rrc.AtoC(text="NEXT", classInp="control-input",           classLbl="control-label",classBtn="control-button")}}         {{rrc.CtoB(text="NEXT", classInp="control-input",           classLbl="control-label",classBtn="control-button")}}         {{rrc.BtoA(text="NEXT", classInp="control-input",           classLbl="control-label",classBtn="control-button")}}       </div>     </div>   </div> </body> </html>

Extending to more states

The state machine component here includes up to four states which is sufficient for many use cases, especially since it’s possible to use multiple independent state machines on one page.

That said, this technique can be used to build a state machine with more than four states. The table below shows how many page states can be built by adding additional bits. Notice that an even number of bits does not collapse efficiently, which is why three and four bits are both limited to four page states.

Bits (rrcs) Machine states Page states
1 2 2
2 4 2
3 8 4
4 16 4
5 32 6

Radio reset controller details

The trick to being able to show, hide, or control an HTML element anywhere on the page without JavaScript is what I call a radio reset controller. With three tags and one line of CSS, the controlling button and controlled element can be placed anywhere after this controller. The controlled side uses a hidden radio button that is checked by default. That radio button is connected to an empty <form> element by an ID. That form has a type="reset" button and another radio input that together make up the controller.

<!-- RRC Controller --> <form id="rrc-form"></form> <label>   Show   <input form="rrc-form" type="radio" name="rrc-group" /> </label> <button type="reset" form="rrc-form">Hide</button>  <!-- Controlled by RRC --> <input form="rrc-form" class="hidden" type="radio" name="rrc-group" checked /> <div class="controlled-rrc">Controlled from anywhere</div>

This shows a minimal implementation. The hidden radio button and the div it controls need to be siblings, but that input is hidden and never needs to be directly interacted with by the user. It is set by a default checked value, cleared by the other radio button, and reset by the form reset button.

input[name='rrc-group']:checked + .controlled-rrc {   display: none; } .hidden {   display: none; }

Only two line of CSS are required to make this work. The :checked pseudo selector connects the hidden input to the sibling it is controlling. It adds the radio input and reset button that can be styled as a single toggle, which is shown in the following Pen:

Accessibility… should you do this?

This pattern works, but I am not suggesting it should be used everywhere for everything. In most cases, JavaScript is the right way to add interactivity to the web. I realize that posting this might get some heat from accessibility and semantic markup experts. I am not an accessibility expert, and implementing this pattern may create problems. Or it may not. A properly labelled button that does something to the page controlled by otherwise-hidden inputs might work out fine. Like anything else in accessibility land: testing is required.

Also, I have not seen anyone else write about how to do this and I think the knowledge is useful — even if it is only appropriate in rare or edge-case situations.


The post A Complete State Machine Made With HTML Checkboxes and CSS appeared first on CSS-Tricks.

You can support CSS-Tricks by being an MVP Supporter.

CSS-Tricks

, , , , ,
[Top]

A Dynamically-Sized Sticky Sidebar with HTML and CSS

Creating page content that sticks to the viewport as you scroll, something like a jump-to-anchor menu or section headings, has never been easier. Throw a position: sticky into your CSS ruleset, set the directional offset (e.g. top: 0) and you’re ready to impress your teammates with minimal effort. Check out this CSS-Tricks article to see some real fancy sticky positioning use cases.

But sticky positioning can get a bit tricky, particularly when it comes to height and the dangerous situation of hiding content in a position that can’t be scrolled to. Let me set the stage and show you the problem and how I fixed it.

I recently worked on a desktop layout that we’re all familiar with: a main content area with a sidebar next to it. This particular sidebar contains action items and filters that are pertinent to the main content. As the page section is scrolled, this component remains fixed to the viewport and contextually accessible.

The layout styling was as easy to implement as I had mentioned earlier. But there was a catch: The height of the component would vary based on its content. I could have capped it with a max-height and set overflow-y: auto to make the component content scrollable. This worked well on my laptop screen and my typical viewport height, but in a smaller viewport with less vertical real estate, the sidebar’s height would exceed the viewport.

When the sticky sidebar height is larger than the viewport, some of its content becomes inaccessible until reaching the bottom of the container, when the element is no longer sticky.

That’s where things got tricky.

Thinking through solutions

I initially considered reaching for a media query. Perhaps I could use a media query to remove the sticky positioning and have the component sit relative to the top of the sidebar container. This would grant access to the entirety of its content. Otherwise, when scrolling the page, the sticky component’s content is cut off at the bottom of the viewport until I reach the end of its parent section.

Then I remembered that the height of the sticky component is dynamic.

What magic value could I use for my media query that would handle such a thing? Perhaps instead I could write a JavaScript function to check if the component flows beyond the viewport boundaries on page load? Then I could update the component’s height…

That was a possibility.

But what if the user resizes their window? Should I use that same function in a resize event handler? That doesn’t feel right. There must be a better way to build this.

Turns out there was and it involved some CSS trickery to get the job done!

Setting up the page section

I started with a flex display on the main element. A flex-basis value was set to the sidebar for a fixed desktop width. Then the article element filled the rest of the available horizontal viewport space.

If you’re curious about how I got the two containers to stack for smaller viewports without a media query, check out The Flexbox Holy Albatross trick.

I added align-self: start to the sidebar so its height wouldn’t stretch with the main article (stretch  is the default value). This gave my positioning properties the ability to cast their magic:

.sidebar {   --offset: var(--space);   /* ... */   position: sticky;   top: var(--offset); }

Check that out! With these two CSS properties, the sidebar element sticks to the top of the viewport with an offset to give it some breathing room. Notice that the top value is set to a scoped CSS custom property. The --offset variable can now be reused on any child element inside the sidebar. This will come in handy later when setting the sticky sidebar component’s maximum height.

You can find a list of global CSS variable declarations in the CodePen demo, including the --space variable used for the offset value in the :root ruleset.

The sticky sidebar

Keep in mind that the component itself is not what is sticky; it’s the sidebar itself. General layout and positioning should typically be handled by the parent. This gives the component more flexibility and makes it more modular to use in other areas of the application.

Let’s dive into the anatomy of this component. In the demo, I’ve removed the decorative properties below to focus on the layout styles:

.component {   display: grid;   grid-template-rows: auto 1fr auto; } 
 .component .content {   max-height: 500px;   overflow-y: auto; }
  • This component uses CSS Grid and the pancake stack idea from 1-Line Layouts to configure the rows of this template. Both the header and footer (auto) adjust to the height of their children while the content (1fr, or one fraction unit) fills up the rest of the open vertical space.
  • A  max-height on the content limits the component’s growth on larger screen sizes. This is unnecessary if it’s preferred that the component stretch to fill the viewport height.
  • overflow-y: auto allows the content to be scrolled when necessary.

When the component is being used in the sidebar, a max-height is needed so that it doesn’t exceed the viewport height. The --offset previously scoped to the .sidebar class is doubled to create a margin on the bottom of the element that matches the top offset of the sticky sidebar:

.sidebar .component {   max-height: calc(100vh - var(--offset) * 2); }

That wraps up the assembly of this sticky sidebar component! After some decorative styles were applied, this prototype became ready for testing and review. Give it a try! Open up the demo in CodePen and click on the grid items to add them to the sidebar. Resize your browser window to see how the component flexes with the viewport while staying in view as you scroll the main content section.


This layout may work well on a desktop browser, but isn’t entirely ideal for smaller devices or viewport widths. However, the code here provides a solid foundation that makes it easy to add improvements to the UI.

One simple idea: A button could be affixed to the viewport window that, when clicked, jumps the page down to the sidebar content. Another idea: The sidebar could be hidden off-screen and a toggle button could slide it in from the left or right. Iteration and user testing will help drive this experience in the right direction.


The post A Dynamically-Sized Sticky Sidebar with HTML and CSS appeared first on CSS-Tricks.

You can support CSS-Tricks by being an MVP Supporter.

CSS-Tricks

, , ,
[Top]

Copyediting with Semantic HTML

Tracking changes is a quintessential copyediting feature for comparing versions of content. While we’re used to tracking changes in a word processing document, we actually have HTML elements capable of that. There are a lot of elements that we can use for this process. The main ones we’ll look at are <del>, <ins> and <mark>. But, as we’ll see, pairing them with other elements — including <u>, <aside> and custom markup — we can get the same sort of visual tracking changes features as something like Word, Google Docs, or even WordPress.

Side-by-side screenshots of how Pages, Google Docs and WordPress display tracked changes.
Different apps have different ways of tracking changes.

Let’s start with the <ins> element.

The <ins> designates text that should be or has been inserted. The verb tense gets a little wonky here because while the <ins> tag is suggesting an edit, it has to have, by virtue of being in the <ins> tag, already been inserted. It’s sorta like saying, “Hey, insert this things that’s technically already there.”

Notice how the browser underlines the inserted text for us. It’s nice to have that sort of visual indication, even if it could be mistaken as an underline using the <u> element, a link, or the CSS text-decoration property.

Let’s pair the insertion with the <del> element, which suggests text that should be or has been deleted.

The browser styles <del> like a strikethrough (<s>) element, but they mean different things. <del> is for content that should be removed/edited out (like that creepy seeming section above) while <s> is for content that’s no longer true or inaccurate (like the letter writer’s belief that that section would be endearing).

OK, great, so we have these semantic HTML elements and they produce some light visual indicators for content that is either inserted or deleted. But there’s something you might not know about these elements: they accept a cite  attribute that can be used to annotate the change.

cite takes a properly formatted URL that provides points somewhere to find the reasons why the change was made. That somewhere could even be an anchor on the existing page.

That’s cool, but one issue is that the citation URL isn’t actually visible or clickable. We could use some CSS magic to display it. But even then, it still won’t take you to the citation when clicked… nor can it be copied. 

That said, it does make semantically clear what’s part of the edit and what is not. If we wrap <ins> and <del> in a link (or even the other way around) it still is not clear whether the link is supposed to be part of the edited content or not.

But! There’s a second attribute that <ins> and <del> both share: datetime. And this is how we can indicate when an edit was made. Again, this is not immediately available to a user, but it keeps semantically clear what is part of the edit and what isn’t. 

HTML’s datetime format, as a machine readable date and time, requires precision and can thus be a bit, well, cranky, But it’s general tenants aren’t too hard. It’s worth noting though that, while datetime is used on other elements, such as <time>, formatting the value in a way that doesn’t include at least a specific day, month, and year on <ins> and <del> would be problematic, obscuring the date and time of an edit rather than provide clarity.

We can make things clearer with a little more CSS magic. For example, we can reveal the datetime value on hover:

Checkboxes work too:

But good editing is far more than simply adding and deleting content. It’s asking questions and figuring out what the heck the author intended. (For me personally, it’s also about saving me from embarrassing spellling and grammar mistooks).

So, meet the <mark> element.

<mark> points out text of special interest to the reader. It usually renders as a yellow background behind the content. 

If you’re the editor and want to write a note to the writer (let’s name that person Stanley Meagher) with suggestions to make Stanly’s letter more awesome (or less creepy, at the very least) and that note is large enough to warrant flow content (i.e. block level elements), then the note can be an <aside> element.

<aside class="note">Mr. Meagher, I highly recommend you remove this list of preferred cheeses and replace it with things you love about the woman you are writing to. While I'm sure there are many people for whom your list would be interesting if not welcome, that list rarely includes a romantic interest in the midst of your profession of love. Though, honestly, if she is as perfect for you as you believe, it may be the exact thing you need to test that theory.</aside>

But often you’ll want to do something inline in order to point something out or make a comment about sentence structure or word choice. Unfortunately there’s no baked in way to do that in HTML, but with a little ingenuity and some CSS you can add a note.

<span class="note">Cheesecake isn't really a "cheese"</span>

The <u> element — long an anathema to web developers for fear of confusion with a link — does actually have a use (I know, I was surprised too). It can be used to point out a misspelling (apparently squiggly and red underlines aren’t a standard browser rendering feature). It should still not be used anywhere it might be confused with an actual link and, when used, it definitely should use a color that distinguishes it from links. Red color may be appropriate to indicate an error. 

<p>Please, <u>Lura</u> tell me your answer. Will you wear my mathlete letter jacket?</p>

As we’ve seen throughout this article, the browser’s default styles for the elements we’ve covered so far are certainly helpful but can also be confusing since they are barely distinguishable from other types of content. If a user does not know that the document is showing edits, then the styling may be misconstrued or misunderstood by the user. I’d therefore suggest some additional or alternate styles to help make it clear what’s going on.

ins {   padding: 0 0.125em;   text-decoration: none;   background-color: lightgreen } del {   padding: 0 0.125em;   text-decoration: none;   background-color: pink; } mark {   padding: 0 0.125em; } .note {   padding: 0 0.125em;   background-color: lightblue; } aside.note {   padding: 0.5em 1em; } u {   text-decoration: none;   border-bottom: 3px red dashed; }

I ask myself the same question every time I learn something new in HTML: How can I needlessly animate this?

It would be great if we could fade up the changes so that when you clicked a checkbox the edits would fade in as well.

The notes and text in <del> tags can’t be faded in with CSS the same way that background colors and paddings can. Also, display: none  results in no fading at all. Everything pops back in place, including the backgrounds. But using a combining the CSS visibility property with a set height and width value of 0 allows the backgrounds to smoothly fade in.


And there you have it: specifications and a few strategies for keeping track of edits on the web (plus an excellent example of how not to write a love letter (or, perhaps, how to write one so perfect that responding positively to it is a sign you’re soulmates).


The post Copyediting with Semantic HTML appeared first on CSS-Tricks.

You can support CSS-Tricks by being an MVP Supporter.

CSS-Tricks

, ,
[Top]

This page is a truly naked, brutalist html quine.

Here’s a fun page coming from secretGeek.net. You don’t normally think “fun” with brutalist minimalism but the CSS trickery that makes it work on this page is certainly that.

The HTML is literally displayed on the page as tags. So, in a sense, the HTML is both the page markup and the content. The design is so minimal (or “naked”) that it’s code leaks through! Very cool.

The page explains the trick, but I’ll paraphrase it here:

  • Everything is a block-level element via { display:block; }
  • …except for anchors, code, emphasis and strong, which remain inline with a,code,em,strong {display:inline}
  • Use ::before and ::after to display the HTML tags as content (e.g. p::before { content: '<p>'})

The page ends with a nice snippet culled from Josh Li’s “58 bytes of css to look great nearly everywhere”:

html {   max-width: 70ch;   padding: 2ch;   margin: auto;   color: #333;   font-size: 1.2em; }

Direct Link to ArticlePermalink


The post This page is a truly naked, brutalist html quine. appeared first on CSS-Tricks.

You can support CSS-Tricks by being an MVP Supporter.

CSS-Tricks

, , , , , ,
[Top]

Smarter Ways to Generate a Deep Nested HTML Structure

Let’s say we want to have the following HTML structure:

<div class='boo'>   <div class='boo'>     <div class='boo'>       <div class='boo'>         <div class='boo'></div>       </div>     </div>   </div> </div>

That’s real a pain to write manually. And the reason why this post was born was being horrified on seeing it generated with Haml like this:

.boo   .boo     .boo       .boo         .boo

There were actually about twenty levels of nesting in the code I saw, but maybe some people are reading thing on a mobile phone, so let’s not fill the entire viewport with boos, even if Halloween is near.

As you can probably tell, manually writing out every level is far from ideal, especially when the HTML is generated by a preprocessor (or from JavaScript, or even a back-end language like PHP). I’m personally not a fan of deep nesting and I don’t use it much myself, but if you’re going for it anyway, then I think it’s worth doing in a manner that scales well and is easily maintainable.

So let’s first take a look at some better solutions for this base case and variations on it and then see some fun stuff done with this kind of deep nesting!

The base solution

What we need here is a recursive approach. For example, with Haml, the following bit of code does the trick:

- def nest(cls, n); -  return '' unless n > 0; -  "<div class='#{cls}'>#{nest(cls, n - 1)}</div>"; end  = nest('👻', 5)

There’s an emoji class in there because we can and because this is just a fun little example. I definitely wouldn’t use emoji classes on an actual website, but in other situations, I like to have a bit of fun with the code I write.

We can also generate the HTML with Pug:

mixin nest(cls, n)   div(class=cls)     if --n       +nest(cls, n)  +nest('👻', 5)

Then there’s also the JavaScript option:

function nest(_parent, cls, n) {   let _el = document.createElement('div'); 	   if(--n) nest(_el, cls, n);    _el.classList.add(cls);   _parent.appendChild(_el) };  nest(document.body, '👻', 5)

With PHP, we can use something like this:

<?php function nest($  cls, $  n) {   echo "<div class='$  cls'>";   if(--$  n > 0) nest($  cls, $  n);   echo "</div>"; }  nest('👻', 5); ?>

Note that the main difference between what each of these produce is related to formatting and white space. This means that targeting the innermost “boo” with .👻:empty is going to work for the Haml, JavaScript and PHP-generated HTML, but will fail for the Pug-generated one.

Adding level indicators

Let’s say we want each of our boos to have a level indicator as a custom property --i, which could then be used to give each of them a different background, for example.

You may be thinking that, if all we want is to change the hue, then we can do that with filter: hue-rotate() and do without level indicators. However, hue-rotate() doesn’t only affect the hue, but also the saturation and lightness. It also doesn’t provide the same level of control as using our own custom functions that depend on a level indicator, --i.

For example, this is something I used in a recent project in order to make background components smoothly change from level to level (the $ c values are polynomial coefficients):

--sq: calc(var(--i)*var(--i)); /* square */ --cb: calc(var(--sq)*var(--i)); /* cube */ --hue: calc(#{$  ch0} + #{$  ch1}*var(--i) + #{$  ch2}*var(--sq) + #{$  ch3}*var(--cb)); --sat: calc((#{$  cs0} + #{$  cs1}*var(--i) + #{$  cs2}*var(--sq) + #{$  cs3}*var(--cb))*1%); --lum: calc((#{$  cl0} + #{$  cl1}*var(--i) + #{$  cl2}*var(--sq) + #{$  cl3}*var(--cb))*1%);  background: hsl(var(--hue), var(--sat), var(--lum));

Tweaking the Pug to add level indicators looks as follows:

mixin nest(cls, n, i = 0)   div(class=cls style=`--i: $  {i}`)     if ++i < n       +nest(cls, n, i)  +nest('👻', 5)

The Haml version is not too different either:

- def nest(cls, n, i = 0); -   return '' unless i < n; -   "<div class='#{cls}' style='--i: #{i}'>#{nest(cls, n, i + 1)}</div>"; end  = nest('👻', 5)

With JavaScript, we have:

function nest(_parent, cls, n, i = 0) {   let _el = document.createElement('div');    _el.style.setProperty('--i', i); 	   if(++i < n) nest(_el, cls, n, i);    _el.classList.add(cls);   _parent.appendChild(_el) };  nest(document.body, '👻', 5)

And with PHP, the code looks like this:

<?php function nest($  cls, $  n, $  i = 0) {   echo "<div class='$  cls' style='--i: $  i'>";   if(++$  i < $  n) nest($  cls, $  n, $  i);   echo "</div>"; }  nest('👻', 5); ?>

A more tree-like structure

Let’s say we want each of our boos to have two boo children, for a structure that looks like this:

.boo   .boo     .boo       .boo       .boo     .boo       .boo       .boo   .boo     .boo       .boo       .boo     .boo       .boo       .boo

Fortunately, we don’t have to change our base Pug mixin much to get this (demo):

mixin nest(cls, n)   div(class=cls)     if --n       +nest(cls, n)       +nest(cls, n)  +nest('👻', 5)

The same goes for the Haml version:

- def nest(cls, n); -   return '' unless n > 0; -   "<div class='#{cls}'>#{nest(cls, n - 1)}#{nest(cls, n - 1)}</div>"; end  = nest('👻', 5)

The JavaScript version requires a bit more effort, but not too much:

function nest(_parent, cls, n) {   let _el = document.createElement('div');      if(n > 1) {     nest(_el, cls, n);     nest(_el, cls, n)   }    _el.classList.add(cls);   _parent.appendChild(_el) };  nest(document.body, '👻', 5)

With PHP, we only need to call the nest() function once more in the if block:

<?php function nest($  cls, $  n) {   echo "<div class='$  cls'>";   if(--$  n > 0) {     nest($  cls, $  n);     nest($  cls, $  n);   }   echo "</div>"; }  nest('👻', 5); ?>

Styling the top level element differently

We could of course add a special .top (or .root or anything similar) class only for the top level, but I prefer leaving this to the CSS:

:not(.👻) > .👻 {   /* Top-level styles*/ }

Watch out!

Some properties, such as transform, filter, clip-path, mask or opacity don’t only affect an element, but also also all of its descendants. Sometimes this is the desired effect and precisely the reason why nesting these elements is preferred to them being siblings.

However, other times it may not be what we want, and while it is possible to reverse the effects of transform and sometimes even filter, there’s nothing we can do about the others. We cannot, for example, set opacity: 1.25 on an element to compensate for its parent having opacity: .8.

Examples!

First off, we have this pure CSS dot loader I recently made for a CodePen challenge:

Here, the effects of the scaling transforms and of the animated rotations add up on the inner elements, as do the opacities.

Next up is this yin and yang dance, which uses the tree-like structure:

For every item, except the outermost one (:not(.☯️) > .☯️), the diameter is equal to half of that of its parent. For the innermost items (.☯️:empty, which I guess we can call the tree leaves), the background has two extra radial-gradient() layers. And just like the first demo, the effects of the animated rotations add up on the inner elements.

Another example would be these spinning candy tentacles:

Each of the concentric rings represents a level of nesting and combines the effects of the animated rotations from all of its ancestors with its own.

Finally, we have this triangular openings demo (note that it’s using individual transform properties like rotate and scale so the Experimental Web Platform features flag needs to be enabled in chrome://flags in order to see it working in Chromium browsers):

Triangular openings (live demo).

This uses a slightly modified version of the basic nesting mixin in order to also set a color on each level:

- let c = ['#b05574', '#f87e7b', '#fab87f', '#dcd1b4', '#5e9fa3']; - let n = c.length;  mixin nest(cls, n)   div(class=cls style=`color: $  {c[--n]}`)     if n       +nest(cls, n)  body(style=`background: $  {c[0]}`)   +nest('🔺', n)

What gets animated here are the individual transform properties scale and rotate. This is done so that we can set different timing functions for them.


The post Smarter Ways to Generate a Deep Nested HTML Structure appeared first on CSS-Tricks.

You can support CSS-Tricks by being an MVP Supporter.

CSS-Tricks

, , , , , ,
[Top]

Editing HTML Like A Boss In VS Code

Here’s a seven minute video from Caleb Porzio that focuses on some of Emmet‘s HTML editing features. You might think of Emmet as that thing that expands abbreviations like table.stats>tr*3>td*3 into glorious, expanded, and perfect HTML. But Emmet has other HTML editing trickery up its sleeve. My favorite is “wrap with abbreviation” (which happens to be Cmd/Ctrl + Shift + A on CodePen), but there are more, like expanding your selection inward and outward and tag changing.

If you haven’t seen it, the Emmet 2 preview on CodePen is pretty neeeeat. It shows you what you’re about to expand into before you do it:

Direct Link to ArticlePermalink


The post Editing HTML Like A Boss In VS Code appeared first on CSS-Tricks.

You can support CSS-Tricks by being an MVP Supporter.

CSS-Tricks

, , , ,
[Top]

Beyond Media Queries: Using Newer HTML & CSS Features for Responsive Designs

Beyond using media queries and modern CSS layouts, like flexbox and grid, to create responsive websites, there are certain overlooked things we can do well to make responsive sites. In this article, we’ll dig into a number tools (revolving around HTML and CSS) we have at the ready, from responsive images to relatively new CSS functions that work naturally whether we use media queries or not.

In fact, media queries become more of a complement when used with these features rather than the full approach. Let’s see how that works.

Truly responsive images

Remember when we could just chuck width: 100% on images and call it a day? That still works, of course, and does make images squishy, but there are a number of downsides that come with it, the most notable of which include:

  • The image might squish to the extent that it loses its focal point.
  • Smaller devices still wind up downloading the full size image.

When using images on the web, we have to make sure they’re optimized in terms of their resolution and size. The reason is to ensure that we have the right image resolution to fit the right device, so we don’t end up downloading really large and heavy images for smaller screens which could end up reducing the performance of a site. 

In simple terms, we’re making sure that larger, high-resolution images are sent to larger screens, while smaller, low-resolution variations are sent to smaller screens, improving both performance and user experience.

HTML offers the <picture> element that allows us specify the exact image resource that will be rendered based on the media query we add. As described earlier, instead of having one image (usually a large, high-resolution version) sent to all screen sizes and scaling it to the viewport width, we specify a set of images to serve in specific situations.

<picture>   <source media="(max-width:1000px)" srcset="picture-lg.png">   <source media="(max-width:600px)" srcset="picture-mid.png">   <source media="(max-width:400px)" srcset="picture-sm.png">   <img src="picture.png" alt="picture""> </picture>

In this example, picture.png is the full-size image. From there, we define the next-largest version of the image, picture-lg.png, and the size reduces in descending order until the smallest version, picture-sm.png. Note that we’re still using media queries in this approach, but it’s the <picture> element itself that is driving the responsive behavior rather than defining breakpoints in the CSS.

The media queries are added appropriately to scale with the sizes of the picture:

  • Viewports that are 1000px and above get picture.png.
  • Viewports that are between 601px and 999px get picture-lg.png.
  • Viewports that are between 401px and 600px get picture-sm.png.
  • Any thing smaller than 400px gets picture-sm.png.

Interestingly, we can also label each image by image density —  1x, 2x, 3x and so forth — after the URL. This works if we have made the different images in proportion to each other (which we did). This allows the browser to determine which version to download based on the screen’s pixel density in addition to the viewport size. But note how many images we wind up defining:

<picture>   <source media="(max-width:1000px)" srcset="picture-lg_1x.png 1x, picture-lg_2x.png 2x, picture-lg_3x.png 3x">   <source media="(max-width:600px)" srcset="picture-mid_1x.png 1x, picture-mid_2x.png 2x, picture-mid_3x.png 3x">   <source media="(max-width:400px)" srcset="picture-small_1x.png 1x, picture-small_2x.png 2x, picture-small_1x.png 3x">   <img src="picture.png" alt="picture""> </picture>

Let’s look specifically at the two tags nested inside the <picture> element: <source> and <img>.

The browser will look for the first <source> element where the media query matches the current viewport width, and then it will display the proper image (specified in the srcset attribute). The <img> element is required as the last child of the <picture> element, as a fallback option if none of the initial source tags matches.

We can also use image density to handle responsive images with just the <img> element using the srcset attribute:

<img  srcset="   flower4x.png 4x,   flower3x.png 3x,   flower2x.png 2x,   flower1x.png 1x  "  src="flower-fallback.jpg" >

Another thing we can do is write media queries in the CSS based on the screen resolution (usually measured in dots per inch, or dpi) of the device itself and not just the device viewport. What this means is that instead of:

@media only screen and (max-width: 600px) {   /* Style stuff */ }

We now have:

@media only screen and (min-resolution: 192dpi) {   /* Style stuff */ }

This approach lets us dictate what image to render based the screen resolution of the device itself, which could be helpful when dealing with high resolution images. Basically, that means we can display high quality pictures for screens that support higher resolutions and smaller versions at lower resolutions. It’s worth noting that, although mobile devices have small screens, they’re usually high resolution. That means it’s probably not the best idea rely on resolution alone when determining which image to render. It could result in serving large, high-resolution images to really small screens, which may not be the version we really want to display at such a small screen size.

body {   background-image : picture-md.png; /* the default image */ } 
 @media only screen and (min-resolution: 192dpi) {   body {     background-image : picture-lg.png; /* higher resolution */   } }

What <picture> gives us is basically the ability to art direct images. And, in keeping with this idea, we can leverage CSS features, like the object-fit property which, when used with object-position, allows us to crop images for better focal points while maintaining the image’s aspect ratio.

So, to change the focal point of an image:

@media only screen and (min-resolution: 192dpi) {   body {     background-image : picture-lg.png;     object-fit: cover;     object-position: 100% 150%; /* moves focus toward the middle-right */   } }

Setting minimum and maximum values in CSS

The min() function specifies the absolute smallest size that an element can shrink to. This function proves really useful in terms of helping text sizes to properly scale across different screen sizes, like never letting fluid type to drop below a legible font size:

html {   font-size: min(1rem, 22px); /* Stays between 16px and 22px */ }

min() accepts two values, and they can be relative, percentage, or fixed units. In this example, we’re telling the browser to never let an element with class .box go below 45% width or 600px, whichever is smallest based on the viewport width:

.box {   width : min(45%, 600px) }

If 45% computes to a value smaller than 600px, the browser uses 45% as the width. Conversely, if  45% computes to a value greater than 600px, then 600px will be used for the element’s width.

The same sort of thing goes for the max() function. It also accepts two values, but rather than specifying the smallest size for an element, we’re defining the largest it can get.

.box {   width : max(60%, 600px) }

If 60% computes to a value smaller than 600px, the browser uses 60% as the width. On the flip side, if 60% computes to a value greater than 600px, then 600px will be used as the element’s width.

And, hey, we can even set a minimum and maximum range instead using the minmax() function:

.box {   width : minmax( 600px, 50% ); /* at least 600px, but never more than 50% */ }

Clamping values

Many of us have been clamoring for clamp() for some time now, and we actually have broad support across all modern browsers (sorry, Internet Explorer). clamp() is the combination of the min() and max() functions, accepting three parameters:

  1. the minimum value,
  2. the preferred value, and
  3. the maximum value

For example:

.box {   font-size : clamp(1rem, 40px, 4rem) }

The browser will set the font at 1rem until the computed value of 1rem is larger than 40px. And when the computed value is above 40px? Yep, the browser will stop increasing the size after it hits 4rem. You can see how clamp() can be used to make elements fluid without reaching for media queries.

Working with responsive units

Have you ever built a page with a large heading or sub-heading and admired how great it looked on a desktop screen, only to check it on a mobile device and find out that’s it’s too large? I have definitely been in this situation and in this section I’ll be explaining how to handle such problems.

In CSS, you can determine sizes or lengths of elements using various units of measurements, and the most used units of measurements includes: px, em, rem, %, vw, and vh. Although, there are several more units that aren’t used as frequently. What’s of interest to us is that px can be considered an absolute unit, while the rest are considered relative units.

Absolute units

A pixel (px) is considered an absolute unit mainly because it’s fixed and does not change based on the measurement of any other element. It can be considered as the base, or root, unit that some other relative units use. Trying to use pixels for responsive behavior can bump into issues because it’s fixed, but they’re great if you have elements that should not be resized at all.

Relative units

Relative units, like %, em, and rem, are better suited to responsive design mainly because of their ability to scale across different screen sizes.

vw: Relative to the viewport’s width
vh: Relative to the viewport’s height
rem: Relative to the root (<html>) element (default font-size is usually 16px )
em: Relative to the parent element
%: Relative to the parent element

Again, the default font size for most browsers is 16px and and that’s what rem units use to generate their computed values. So, if a user adjusts the font size on the browser, everything on the page scales properly depending on the root size. For example, when dealing a root set at 16px, the number you specify will multiply that number times the default size. For example:

.8rem = 12.8px (.8 * 16) 1rem = 16px (1 * 16) 2rem = 32px (2 * 16)

What if either you or the user changes the default size? As we said already, these are relative units and the final size values will be based off of the new base size. This proves useful within media queries, where you just change the font size and the entire page scales up or down accordingly.

For example, if you changed the font-size to 10px within the CSS, then the calculated sizes would end up being:

html {   font-size : 10px; }
1rem = 10px (1 * 10) 2rem = 20px (2 * 10) .5rem = 5px (.5 * 10)

Note: This also applies to percentage %. For instance:

100% = 16px; 200% = 32px;  50% = 8px;

And what’s the difference between rem and em units? It’s what the unit uses as its base element. rem calculates values using the font size of the root (<html>) element, whereas an element declaring em values references the font size of the parent element that contains it. If the size of specified parent element is different from the root element (e.g. the parent elements is 18px but the root element is 16px) then em and rem will resolve to different computed values. This gives us more fine-grained control of how our elements respond in different responsive contexts.

vh is an acronym for viewport height, or the viewable screen’s height. 100vh represent 100% of the viewport’s height (depending on the device). In the same vein, vw stands for viewport width, meaning the viewable screen’s width of the device, and 100vw literally represents 100% of the viewport’s width.

Moving beyond media queries

See that? We just looked at a number of really powerful and relatively new HTML and CSS features that give us additional (and possible more effective) ways to build for responsiveness. It’s not that these new-fangled techniques replace what we’ve been doing all along. They are merely more tools in our developer tool belt that give us greater control to determine how elements behave in different contexts. Whether it’s working with font sizes, resolutions, widths, focal points, or any number of things, we have more fine-grain control of the user experience than ever before.

So, next time you find yourself working on a project where you wish you had more control over the exact look and feel of the design on specific devices, check out what native HTML and CSS can do to help — it’s incredible how far things have come along.


The post Beyond Media Queries: Using Newer HTML & CSS Features for Responsive Designs appeared first on CSS-Tricks.

You can support CSS-Tricks by being an MVP Supporter.

CSS-Tricks

, , , , , , , ,
[Top]

HTML for Subheadings and Headings

Let’s say you have a double heading situation going on. A little one on top of a big one. It comes up, I dunno, a billion times a day, I’d say. What HTML do you go for? Dare I say, it depends? But have you considered all the options? And how those options play out semantically and accessibility-y?

As we do around here sometimes, let’s take a stroll through the options.

The visual examples

Let’s assume these are not the <h1> on the page. Not that things would be dramatically different if one of them was, but just to set the stage. I find this tends to come up in subsections or cards the most.

Here’s an example a friend brought up in a conversation the other day:

Here’s one that I worked on also just the other day:

And here’s a classic card:

Option 1: The ol’ <h3> then <h2>

The smaller one is on the top, and the bigger one is below, and obviously <h3> is always smaller than an <h2> right?

<h3>Subheading</h3> <h2>Heading</h2>

This is probably pretty common thinking and my least favorite approach.

I’d rather see class names in use so that the styling is isolated to those classes.

<h3 class="card-subhead">Subheading</h3> <h2 class="card-head">Heading</h2>

Don’t make semantic choices, particularly those that affect accessibility, based on this purely visual treatment.

The bigger weirdness is using two heading elements at all. Using two headings for a single bit of content doesn’t feel right. The combination feels like: “Hey here’s a major new section, and then here’s another subheading because there will be more of them in this subsection so this one is just for this first subsection.” But then there are no other subsections and no other subheadings. Even if that isn’t weird, the order is weird with the subsection header coming first.

If you’re going to use two different heading elements, it seems to me the smaller heading is almost more likely to make more sense as the <h2>, which leads us to…

Option 2: Small ‘n’ mighty <h2> and <h3>

If we’ve got classes in place, and the subheading works contextually as the more dominant heading, then we can do this:

<h2 class="card-subheading">Subheading</h2> <h3 class="card-heading">Heading</h3>

Just because that <h2> is visually smaller doesn’t mean it still can’t be the dominant heading in the document outline. If you look at the example from CodePen above, the title “Context Switching” feels like it works better as a heading than the following sentence does. I think using the <h2> on that smaller header works fine there, and keeps the structure more “normal” (I suppose) with the <h2> coming first.

Still, using two headings for one section still feels weird.

Option 3: One header, one div

Perhaps only one of the two needs to be a heading? That feels generally more correct to me. I’ve definitely done this before:

<div class="card-subheading">Subheading</div> <h3 class="card-heading">Heading</h3>

That feels OK, except for the weirdness that the subhead might have relevant content and people could potentially miss that if they navigated to the head via screenreader and read from there forward. I guess you could swap the visual order…

<hgroup> <!-- hgroup is deprecated, just defiantly using it anyway -->    <h3 class="card-heading">Heading</h3>   <div class="card-subheading">Subheading</div>  </hgroup>
hgroup {   display: flex;   flex-direction: column; } hgroup .card-subheading {   /* Visually, put on top, without affecting source order */   order: -1; }

But I think messing with visual order like that is generally a no-no, as in, awkward for sighted screenreader users. So don’t tell anybody I showed you that.

Option 4: Keep it all in one heading

Since we’re only showing a heading for one bit of content anyway, it seems right to only use a single header.

<h2>   <strong>Subheading</strong>   Heading </h2>

Using the <strong> element in there gives us a hook in the CSS to do the same type of styling. For example…

h2 strong {   display: block;   font-size: 75%;   opacity: 0.75; }

The trick here is that the headings then need to work/read together as one. So, either they read together naturally, or you could use a colon : or something.

<h2>   <strong>New Podcast:</strong>   Struggling with Basic HTML </h2>

ARIA Role

It turns out that there is an ARIA role dedicated to subtitles:

So like:

<h2 class="card-heading">Heading</h2> <div role="doc-subtitle">Subheading</div>

I like styles based on ARIA roles in general (because it demands their proper use), so the styling could be done directly with it:

[role="doc-subtitle"] { }

Testing from Steve and Léonie suggest that browsers generally treat it as a “heading without a level.” JAWS is the exception, which treats it like an <h2>. That seems OK… maybe? Steve even thinks putting the subheading first is OK.

The bad and the ugly

What’s happening here is the subheading is providing general context to the heading — kinda like labelling it:

<label for="card-heading-1">Subheading</label> <h2 id="card-heading-1" class="card-heading">Heading</h2>

But we’re not dealing in form elements here, so that’s not recommended. Another way to make it a single heading would be to use a pseudo-element to place the subhead, like:

<h2 class="card-heading" data-subheading="Subheading">Heading</h2>
.card-head::before {   content: attr(data-subheading);   display: block;   font-size: 75%;   opacity: 0.75; }

It used to be that screen readers ignored pseudo-content, but it’s gotten better, though still not perfect. That makes this only slightly more usable, but the text is still un-selectable and not on-page-findable, so I’d rather not go here.


The post HTML for Subheadings and Headings appeared first on CSS-Tricks.

You can support CSS-Tricks by being an MVP Supporter.

CSS-Tricks

, ,
[Top]

SVG Title vs. HTML Title Attribute

You know the title attribute? I can do this:

<div title="The Title">   I'm a div with a `title` </div>

And now if I’m on a device with a mouse pointer and hover the cursor over that element, I get…

Screenshot of standard text saying I'm a div with a title. A light gray tooltip is floating above the text next to the cursor that says The Title.

Which, uh, I guess is something. I sometimes use it for things like putting an expanded date or time on an element that uses shorthand for it. It’s a tiny bit of UX helpfulness reserved exclusively for sighted mouse users.

But it’s not particularly useful, as I understand it. Ire Aderinokun dug into how it’s used for the <abbr> element (a commonly cited example) and found that it’s not-so-great alone. She suggests a JavaScript-enhanced pattern. She also mentions that JAWS has a setting for announcing titles in there, so that’s interesting (although it sounds like it’s off by default).

I honestly just don’t know how useful title is for screen readers, but it’s certainly going to be nuanced.

I did just learn something about titles though… this doesn’t work:

<!-- Incorrect usage --> <svg title="Checkout"> </svg>

If you hover over that element, you won’t get a title display. You have to do it like this:

<!-- Correct usage --> <svg>   <title>Checkout</title>      <!-- More detail -->   <desc>A shopping cart icon with baguettes and broccoli in the cart.</desc> </svg>

Which, interestingly, Firefox 79 just started supporting.

When you use title like that, the hoverable area to reveal the title popup is the entire rectangle of the <svg>.

I was looking at all this because I got an interesting email from someone who was in a situation where the title popup only seemed to come up when hovering over the “filled in” pixels of an SVG, and not where transparent pixels were. Weird, I thought. I couldn’t replicate in my testing either.

Turns out there is a situation like this. You can apply a <title> within a <use> element, then the title only applies to those pixels that come in via the <use>.

If you remove the “white part” title, you’ll see the “black part” only comes up over the black pixels. Seems to be consistent across browsers. Just something to watch out for if that’s how you apply titles.


The post SVG Title vs. HTML Title Attribute appeared first on CSS-Tricks.

You can support CSS-Tricks by being an MVP Supporter.

CSS-Tricks

, ,
[Top]