Monday, December 2, 2024
HomeProgrammingOne Of These "Onboarding" UIs, With Anchor Positioning

One Of These “Onboarding” UIs, With Anchor Positioning


Welcome to “Anchor Positioning 101” the place we will probably be exploring this fascinating new CSS characteristic. Our textbook for this class would be the in depth “Anchor Positioning Information” that Juan Diego Rodriguez printed right here on CSS-Methods.

I’m excited for this one. A few of chances are you’ll bear in mind when CSS-Methods launched the “Flexbox Format Information” or the “Grid Format Information” — I definitely do and nonetheless have them each bookmarked! I spend quite a lot of time flipping between tabs to ensure I’ve the precise syntax in my “experimental” CodePens.

I’ve been experimenting with CSS anchor positioning just like the “good outdated days” since Juan printed his information, so I figured it’d be enjoyable to share among the pleasure, be taught a bit, experiment, and naturally: construct stuff!

CSS Anchor Positioning introduction

Anchor positioning lets us connect — or “anchor” — one component to a number of different components. Greater than that, it permits us to outline how a “goal” component (that’s what we name the component we’re attaching to an anchor component) is positioned subsequent to the anchor-positioned component, together with fallback positioning within the type of a brand new @position-try at-rule.

Probably the most hand-wavy strategy to clarify the advantages of anchor positioning is to think about it as a strong enhancement to place: absolute; because it helps absolutely-positioned components do what you anticipate. Don’t fear, we’ll see how this works as we go.

Anchor positioning is at the moment a W3C draft spec, so it’s contemporary. It’s marked as “restricted availability” in Baseline which on the time of writing means it’s restricted to Chromium-based browsers (variations 125+). That stated, the thoughtful people over at Oddbird have a polyfill out there that’ll assist out different browsers till they ship help.

Desktop

Chrome Firefox IE Edge Safari
125 No No 125 No

Cell / Pill

Android Chrome Android Firefox Android iOS Safari
131 No 131 No

Oddbird contributes polyfills for many new CSS options and also you (sure, you!) can help their work on Github or Open Collective!

Tab Atkins-Bittner, contributing creator to the W3C draft spec on anchor positioning, spoke on the subject at CSS Day 2024. The total convention discuss is out there on YouTube:

Right here at CSS-Methods, Juan demonstrated how one can combine and match anchor positioning with view-driven animations for an superior floating notes impact:

Entrance-end pal Kevin Powell just lately launched a video demonstrating how “CSS Popover + Anchor Positioning is Magical”.

And at last, within the custom of “making enjoyable video games to be taught CSS,” Thomas Park launched Anchoreum (a “Flexbox Froggy“-type recreation) to find out about CSS anchor positioning. Extremely advocate checking this out to get the dangle of the position-area property!

The homework

OK, now that we’re caught up on what CSS anchor positioning is and the joy surrounding it, let’s discuss what it does. Tethering a component to a different component? That has a lot of potential. Fairly just a few cases I can bear in mind the place I’ve needed to battle with absolute positioning and z-index so as to get one thing positioned good.

Let’s take a fast take a look at the fundamental syntax. First, we want two components, an anchor-positioned component and the goal component that will probably be tethered to it.

<!-- Anchor component -->
<div id="anchor">
  Anchor
</div>

<!-- Goal component -->
<div id="goal">
  Goal
</div>

We set a component as an anchor-positioned component by offering it with an anchor-name. This can be a distinctive identify of our selecting, nevertheless it wants the double-dash prefix, like CSS customized properties.

#anchor {
  anchor-name: --anchor;
}

As for our goal component, we’ll have to set place: absolute; on it in addition to inform the component what anchor to tether to. We do this with a brand new CSS property, position-anchor utilizing a price that matches the anchor-name of our anchor-positioned component.

#anchor {
  anchor-name: --anchor;
}

#goal {
  place: absolute;
  position-anchor: --anchor;
}

Could not seem like it but, however now our two components are connected. We are able to set the precise positioning on the goal component by offering a position-area. To place our goal component, position-area creates an invisible 3×3 grid over the anchor-positioned component. Utilizing positioning key phrases, we will designate the place the goal component seems close to the anchor-positioned component.

#goal {
  place: absolute;
  position-anchor: --anchor;
  position-area: high heart;
}

Now we see that our goal component is anchored to the top-center of our anchor-positioned component!

red rectangle labelled "target" attached to the top of a blue square labelled "Anchor"

Anchoring pseudo-elements

Whereas taking part in with anchor positioning, I seen you may anchor pseudo-elements, simply the identical as some other component.

#anchor {
  anchor-name: --anchor;

  &::earlier than {
    content material: "Goal";
    place: absolute;
    position-anchor: --anchor;
    left: anchor(heart);
    backside: anchor(heart);
  }
}

a semi-transparent red square labelled "Target" is attached to the upper corner of a blue square labelled "Anchor"

Is perhaps helpful for including design prospers to components or including performance as some type of indicator.

Shifting anchors

One other fast experiment was to see if we will transfer anchors. And it seems that is attainable!

Discover using anchor() features as an alternative of position-area to place the goal component.

#goal {
  place: absolute;
  position-anchor: --anchor-one;
  high: anchor(backside);
  left: anchor(left);
}

CSS anchor features are an alternate strategy to place goal components based mostly on the computed values of the anchor-positioned component itself. Right here we’re setting the goal component’s high property worth to match the anchor-positioned component’s backside worth. Equally, we will set the goal’s left property worth to match the anchor-positioned component’s left worth.

Hovering over the container component swaps the position-anchor from --anchor-one to --anchor-two.

.container:hover {
  #goal {
    position-anchor: --anchor-two;
  }
}

We’re additionally capable of set a transition as we place the goal utilizing high and left, which makes it swap easily between anchors.

Together with being the primary to launch CSS anchor-positioning, the Chrome dev workforce just lately launched new pseudo-selectors associated to the <particulars> and <abstract> components. The ::details-content pseudo-selector means that you can fashion the “hidden” a part of the <particulars> component.

With this data, I assumed: “can I anchor it?” and certain sufficient, you may!

Once more, that is definitely not prepared for prime-time, but it surely’s at all times enjoyable to experiment!

Sensible examinations

Let’s take this a bit additional and deal with extra sensible challenges utilizing CSS anchor positioning. Please remember that all these examples are Chrome-only on the time of writing!

Tooltips

One of the easy use instances for CSS anchor positioning is presumably a tooltip. Makes quite a lot of sense: hover over an icon and a label floats close by to clarify what the icon does. I didn’t fairly need to make one more tutorial on how one can make a tooltip and fortunately for me, Zell Liew just lately wrote an article on tooltip greatest practices, so we will focus purely on anchor positioning and confer with Zell’s work for the semantics.

Now, let’s take a look at certainly one of these tooltips:

<!-- ... -->;
<li class="toolbar-item">;
  <button kind="button" 
    id="inbox-tool" 
    aria-labelledby="inbox-label" 
    class="software">
    <svg id="inbox-tool-icon">
      <!-- SVG icon code ... -->
    </svg>
  </button>

  <div id="inbox-label" function="tooltip">
    <p>Inbox</p>
  </div>
</li>
<!-- ... -->

The HTML is structured in a manner the place the tooltip component is a sibling of our anchor-positioned <button>, discover the way it has the [aria-labelledby] attribute set to match the tooltip’s [id]. The tooltip itself is a generic <div>, semantically enhanced to turn out to be a tooltip with the [role="tooltip"] attribute. We are able to additionally use [role="tooltip"] as a semantic selector so as to add widespread kinds to tooltips, together with the tooltip’s positioning relative to its anchor.

First, let’s flip our button into an anchored component by giving it an anchor-name. Subsequent, we will set the goal component’s position-anchor to match the anchor-name of the anchored component. By default, we will set the tooltip’s visibility to hidden, then utilizing CSS sibling selectors, if the goal component receives hover or focus-visible, we will then swap the visibility to seen.

/* Anchor-positioned Component */
#inbox-tool {
  anchor-name: --inbox-tool;
}

/* Goal component */
[role="tooltip"]#inbox-label {
  position-anchor: --inbox-tool
}

/* Goal positioning */
[role="tooltip"] {
  place: absolute;
  position-area: finish heart;
  /* Hidden by default */
  visibility: hidden;
}

/* Seen when software is hovered or receives focus */
.software:hover + [role="tooltip"],
.software:focus-visible + [role="tooltip"] {
  visibility: seen;
}

Ta-da! Right here we have now a working, CSS anchor-positioned tooltip!

As customers of contact units aren’t capable of hover over components, chances are you’ll need to discover toggletips as an alternative!

Floating disclosures

Disclosures are one other widespread element sample that is perhaps an ideal use case for anchor positioning. Disclosures are sometimes a element the place interacting with a toggle will open and shut a corresponding component. Consider the nice ol’ <element>/<abstract> HTML component duo, for instance.

At the moment, if you’re trying to create a disclosure-like element which floats over different parts of your consumer interface, you is perhaps in for some JavaScript, absolute positioning, and z-index associated troubles. Quickly sufficient although, we’ll have the ability to mix CSS anchor positioning with one other newer platform characteristic [popover] to create some extremely easy (and semantically correct) floating disclosure components.

The Popover API supplies a non-modal strategy to elevate components to the top-layer, whereas additionally baking in some nice performance, comparable to gentle dismissals.

Zell additionally has extra data on popovers, dialogs, and modality!

One of many extra widespread patterns you may contemplate as a “floating disclosure”-type element is a dropdown menu. Right here is the HTML we’ll work with:

<nav>
  <button id="anchor">Toggle</button>
  <ul id="goal">
    <li><a href="#">Hyperlink 1</a></li>
    <li><a href="#">Hyperlink 2</a></li>
    <li><a href="#">Hyperlink 3</a></li>
  </ul>
</nav>

We are able to set our goal component, on this case the <ul>, to be our popover component by including the [popover] attribute.

To regulate the popover, let’s add the attribute [popoveraction="toggle"] to allow the button as a toggle, and level the [popovertarget] attribute to the [id] of our goal component.

<nav>
  <button id="anchor" 
          popoveraction="toggle"
          popovertarget="goal">
    Toggle
  </button>

  <ul id="goal" popover>
    <li><a href="#">Hyperlink 1</a></li>
    <li><a href="#">Hyperlink 2</a></li>
    <li><a href="#">Hyperlink 3</a></li>
  </ul>
</nav>

No JavaScript is critical, and now we have now a toggle-able [popover] disclosure component! The issue is that it’s nonetheless not tethered to the anchor-positioned component, let’s repair that in our CSS.

First, as it is a popover, let’s add a small little bit of styling to take away the intrinsic margin popovers obtain by default from browsers.

ul[popover] {
  margin: 0;
}

Let’s flip our button into an anchor-positioned component by offering it with an anchor-name:

ul[popover] {
  margin: 0;
}

#anchor {
  anchor-name: --toggle;
}

As for our goal component, we will connect it to the anchor-positioned component by setting its place to absolute and the position-anchor to our anchor-positioned component’s anchor-name:

ul[popover] {
  margin: 0;
}

#anchor {
  anchor-name: --toggle;
}

#goal {
  place: absolute;
  position-anchor: --toggle;
}

We are able to additionally alter the goal’s positioning close to the anchor-positioned component with the position-area property, much like what we did with our tooltip.

ul[popover] {
  margin: 0;
}

#anchor {
  anchor-name: --toggle;
}

#goal {
  place: absolute;
  position-anchor: --toggle;
  position-area: backside;
  width: anchor-size(width);
}

You might discover one other CSS anchor operate in right here, anchor-size()! We are able to set the goal’s width to match the width of the anchor-positioned component through the use of anchor-size(width).

There may be yet one more neat factor we will apply right here, fallback positioning! Let’s contemplate that perhaps this dropdown menu may typically be positioned on the backside of the viewport, both from scrolling or another purpose. We don’t actually need it to overflow or trigger any additional scrolling, however as an alternative, swap to an alternate location that’s seen to the consumer.

Anchor positioning makes this attainable with the postion-try-fallbacks property, a manner to offer an alternate location for the goal component to show close to an anchor-positioned component.

#goal {
  place: absolute;
  position-anchor: --toggle;
  position-area: backside;
  postion-try-fallbacks: high;
  width: anchor-size(width);
}

To maintain issues easy for our demo, we will add the other worth of the worth of the postion-area property: high.

Purchasing cart element

We all know how one can make a tooltip and a disclosure component, now let’s construct upon what we’ve realized to this point and create a neat, interactive buying cart element.

Let’s take into consideration how we need to mark this up. First, we’ll want a button with a buying cart icon:

<button id="shopping-cart-toggle">
  <svg id="shopping-cart-icon" />
    <!-- SVG icon code ... -->
  </svg>
</button>

We are able to already reuse what we realized with our tooltip kinds to offer a functioning label for this toggle. Let’s add the category .software to the button, then embrace a tooltip as our label.

<!-- Toggle -->
<button id="shopping-cart-toggle" 
        aria-labelledby="shopping-cart-label"
        class="software">
  <svg id="shopping-cart-icon" />
    <!-- SVG icon code ... -->
  </svg>
</button>

<!-- Tooltip -->
<div id="shopping-cart-label" 
     function="tooltip" 
     class="tooltip">
  <p>Purchasing Cart</p>
</div>

We’ll have to specify our <button> is an anchor-positioned component in CSS with an anchor-name, which we will additionally set because the tooltip’s position-anchor worth to match.

button#shopping-cart-toggle {
    anchor-name: --shopping-cart-toggle;
}

[role="tooltip"]#shopping-cart-label {
    position-anchor: --shopping-cart-toggle;
}

Now we should always have a nice-looking tooltip labeling our buying cart button!

However wait, we would like this factor to do greater than that! Let’s flip it right into a disclosure element that reveals a listing of things contained in the consumer’s cart. As we wish to have a floating user-interface with just a few actions included, we should always contemplate a <dialog> component. Nevertheless, we don’t essentially need to be blocking background content material, so we will go for a non-modal dialog utilizing the[popover] attribute once more!

<!-- Toggle -->
<button id="shopping-cart-toggle" 
	aria-labelledby="shopping-cart-label"
	class="software"
	popovertarget="shopping-cart"
	popoveraction="toggle">
  <svg id="shopping-cart-icon" />
    <!-- SVG icon code ... -->
  </svg>
</button>
<!-- Tooltip -->
<div id="shopping-cart-label" 
     function="tooltip" 
     class="tooltip">
  <p>Purchasing Cart</p>
</div>
<!-- Purchasing Cart -->
<dialog id="shopping-cart" popover>
  <!-- Purchasing cart template... -->
  <button popovertarget="shopping-cart" popoveraction="shut">
    Dismiss Cart
  </button>
</dialog>

To regulate the popover, we’ve added [popovertarget="shopping-cart"] and [popoveraction="toggle"] to our anchor-positioned component and included a second button inside the <dialog> that can be used to shut the dialog with [popoveraction="close"].

To anchor the buying cart <dialog> to the toggle, we will set position-anchor and position-area:

#shopping-cart {
  position-anchor: --shopping-cart;
  position-area: finish heart;
}

At this level, we should always take a second to appreciate that we have now tethered two components to the identical anchor!

We received’t cease there, although. There may be yet one more enhancement we will make to essentially present how useful anchor positioning might be: Let’s add a notification badge to the component to explain what number of objects are contained in the cart.

Let’s place the badge inside of our anchor-positioned component this time.

<!-- Toggle -->
<button id="shopping-cart-toggle" 
	aria-labelledby="shopping-cart-label"
	class="software"
	popovertarget="shopping-cart"
        popoveraction="toggle">

  <svg id="shopping-cart-icon" />
    <!-- SVG icon code ... -->
  </svg>

  <!-- Notification Badge -->
  <div id="shopping-cart-badge" class="notification-badge">
    1
  </div>
</button>
<!-- ... -->

We are able to enhance our tooltip to incorporate verbiage about what number of objects are within the cart:

<!-- Tooltip -->
<div id="shopping-cart-label" 
     function="tooltip">
  <p>Purchasing Cart</p>
  <p>(1 merchandise in cart)</p>
</div>

Now the accessible identify of our anchor-positioned component will probably be learn as Purchasing Cart (1 merchandise in cart), which helps present context to assistive applied sciences like display readers.

Let’s tether this notification badge to the identical anchor as our tooltip and buying cart <dialog>, we will do that by setting the position-anchor property of the badge to --shopping-cart-toggle:

#shopping-cart-badge {
  place: absolute;
  position-anchor: --shopping-cart-toggle;
}

Let’s take a look at positioning. We don’t need it beneath or subsequent to the anchor, we would like it overlapping, so we will use CSS anchor features to place it based mostly on the anchor-positioned component’s dimensions.

#shopping-cart-badge {
  place: absolute;
  position-anchor: --shopping-cart-toggle;
  backside: anchor(heart);
  left: anchor(heart);
}

Right here we’re setting the backside and left of the goal component to match the anchor’s heart. This locations it within the upper-right nook of the SVG icon!

black shopping cart icon with a red circle badge containing the number 1

Of us, this implies we have now three components anchored now. Isn’t that incredible?

Combining issues

To place these anchor-positioned components into perspective, I’ve mixed all of the methods we’ve realized to this point right into a extra acquainted setting:

Disclosure elements, dropdown menus, tooltips (and toggletips!), in addition to notification badges all made a lot less complicated utilizing CSS anchor positioning!

Remaining challenge

As a closing challenge for myself (and to convey this entire factor round full-circle), I made a decision to attempt to construct a CSS anchor-positioned-based onboarding software. I’ve beforehand tried to construct a software like this at work, which I referred to as “HandHoldJS” and it… nicely, it didn’t go so nice. I managed to have quite a lot of the core performance working utilizing JavaScript, but it surely meant preserving monitor of various positions and many bizarre issues stored occurring!

Let’s see if we will do higher with CSS anchor positioning.

Be at liberty to take a look at the code on CodePen! I went down fairly a rabbit gap on this one, so I’ll present a little bit of a high-level overview right here.

<hand-hold> is a local customized component that works totally within the gentle DOM. It type of falls into the class of an HTML internet element, as it’s largely based mostly on enabling its inside HTML. You’ll be able to specify tour stops to any component on the web page by including [data-tour-stop] attributes with values within the order you need the tour to happen.

Contained in the <hand-hold> component comprises a <button> to begin the tour, a <dialog> component to include the tour data, <part> components to separate content material between tour stops, a fieldset[data-handhold-navigation] component which holds navigation radio buttons, in addition to one other <button> to finish the tour.

Every <part> component corresponds to a tour cease with an identical [data-handhold-content] attribute utilized. Utilizing JavaScript, <hand-hold> dynamically updates tour stops to be anchor-positioned components, which the <dialog> can connect itself (there’s a sneaky pseudo-element connected to the anchor to spotlight the tour cease component!).

Though the <dialog> component is connected through CSS anchor positioning, it additionally strikes inside the DOM to look subsequent to the anchor-position component within the accessibility tree. The (well-meaning) intention right here is to assist present extra context to those that could also be navigating through assistive units by determining which component the dialog is referring to. Imagine me, although, this factor is removed from good as an accessible consumer expertise.

Additionally, for the reason that <dialog> strikes all through the DOM, sadly, a easy CSS transition wouldn’t suffice. One other trendy browser characteristic to the rescue but once more, as we will go a DOM manipulation operate right into a View Transition, making the transitions really feel smoother!

There may be nonetheless quite a bit to check with this, so I’d not advocate utilizing <hand-hold> in a manufacturing setting. If for no different purpose than browser help is fairly restricted in the intervening time!

That is simply an experiment to see what I might cook dinner up utilizing CSS anchor positioning, I’m excited for the potential!

Class dismissed!

After seeing what CSS anchor positioning is able to, I’ve suspicions that it could change quite a lot of the methods we write CSS, much like the introduction of flexbox or grid.

I’m excited to see what different consumer interface patterns might be completed with anchor positioning, and I’m much more excited to see what the neighborhood will do with it as soon as it’s extra broadly out there!

RELATED ARTICLES

LEAVE A REPLY

Please enter your comment!
Please enter your name here

- Advertisment -
Google search engine

Most Popular

Recent Comments