Working With Multiple CSS Anchors And Popovers Inside The WordPress Loop | CSS-Tricks

Working With Multiple CSS Anchors And Popovers Inside The WordPress Loop | CSS-Tricks


I know, super niche, but it could be any loop, really. The challenge is having multiple tooltips on the same page that make use of the Popover API for toggling goodness and CSS Anchor Positioning for attaching a tooltip to its respective anchor element.

There’s plenty of moving pieces when working with popovers:

  • A popover needs an ID (and an accessible role while we’re at it).
  • A popovertarget needs to reference that ID.
  • IDs have to be unique for semantics, yes, but also to hook a popover into a popovertarget.

That’s just the part dealing with the Popover API. Turning to anchors:

  • An anchor needs an anchor-name.
  • A target element needs to reference that anchor-name.
  • Each anchor-name must be unique to attach the target to its anchor properly.

The requirements themselves are challenging. But it’s more challenging working inside a loop because you need a way to generate unique IDs and anchor names so everything is hooked up properly without conflicting with other elements on the page. In WordPress, we query an array of page objects:

$property_query = new WP_Query(array(
  'post_type' => 'page',
  'post_status' => 'publish',
  'posts_per_page' => -1, // Query them all!
  'orderby' => 'title',
  'order' => "ASC"
));

Before we get into our while() statement I’d like to stub out the HTML. This is how I want a page object to look inside of its container:



OK, let’s stub out the tooltip markup while we’re here, focusing just inside the

element since that’s what represents a single page.

accent-color

Experimental feature

With me so far? We’ll start with the Popover side of things. Right now we have a

Experimental feature

The popover has an ID of #experimental-label. The anchor references it in the popovertarget attribute. This connects them but also connects other tooltips that are on the page. What would be ideal is to have a sequence of IDs, like:


...

...

...

We can make the page query into a function that we call:

function letterOutput($letter, $propertyID) {
  $property_query = new WP_Query(array(
    'post_type' => 'page',
    'post_status' => 'publish',
    'posts_per_page' => -1, // Query them all!
    'orderby' => 'title',
    'order' => "ASC"
  ));
}

And when calling the function, we’ll take two arguments that are specific only to what I was working on. If you’re curious, we have a structured set of pages that go Almanac → Type → Letter → Feature (e.g., Almanac → Properties → A → accent-color). This function outputs the child pages of a “Letter” (i.e., A → accent-color, anchor-name, etc.). A child page might be an “experimental” CSS feature and we’re marking that in the UI with tooltops next to each experimental feature.

We’ll put the HTML into an object that we can return when calling the function. I’ll cut it down for brevity…

$html .= '
'; $html .= ''; $html .= '

accent-color

'; $html .= ''; $html .= ''; $html .= '

'; // ... $html .= '

'; $html .= '
'; $html .= '
'; $html .= '
'; return $html;

WordPress has some functions we can leverage for looping through this markup. For example, we can insert the_title() in place of the hardcoded post title:

$html .= '

' . get_the_title(); . '

';

We can also use get_the_id() to insert the unique identifier associated with the post. For example, we can use it to give each

element a unique ID:

$html .= '
';

This is the secret sauce for getting the unique identifiers needed for the popovers:

// Outputs something like `id="experimental-label-12345"`
$html .= '

We ought to do the same thing to the .tooltip element itself to distinguish one from another:

$html .= '';

I can’t exactly recreate a WordPress instance in a CodePen demo, but here’s a simplified example with similar markup:

The popovers work! Clicking either one triggers its respective popover element. The problem you may have realized is that the targets are both attached to the same anchor element — so it looks like we’re triggering the same popover when clicking either button!

This is the CSS side of things. What we need is a similar way to apply unique identifiers to each anchor, but as dashed-idents instead of IDs. Something like this:

/* First tooltip */
#info-tip-1 {
  [popovertarget] {
    anchor-name: --infotip-1;
  }

  [popover] {
    position-anchor: --infotip-1;
    top: anchor(--infotip-1 -15%);
    left: anchor(--infotip-1 100%);
  }
}

/* Second tooltip */
#info-tip-2 {
  [popovertarget] {
    anchor-name: --infotip-1;
  }

  [popover] {
    position-anchor: --infotip-1;
    top: anchor(--infotip-1 -15%);
    left: anchor(--infotip-1 100%);
  }
}

/* Rest of tooltips... */

This is where I feel like I had to make a compromise. I could have leveraged an @for loop in Sass to generate unique identifiers but then I’d be introducing a new dependency. I could also drop a tag directly into the WordPress template and use the same functions to generate the same post identifiers but then I’m maintaining styles in PHP.

I chose the latter. I like having dashed-idents that match the IDs set on the .tooltip and popover. It ain’t pretty, but it works:

$html .= '
'

We’re technically done!

The only thing I had left to do for my specific use case was add a conditional statement that outputs the tooltip only if it is marked an “Experimental Feature” in the CMS. But you get the idea.

Isn’t there a better way?!

Yes! But not quite yet. Bramus proposed a new ident() function that, when it becomes official, will generate a series of dashed idents that can be used to name things like the anchors I’m working with and prevent those names from colliding with one another.

...
...
...
...
...

/* Hypothetical example — does not work! */
.group-item { 
  anchor-name: ident("--infotip-" attr(id) "-anchor");
  /* --infotip-item-1-anchor, --infotip-item-2-anchor, etc. */
}

Let’s keep our fingers crossed for that to hit the specifications soon!



Source link

Leave a Reply

Your email address will not be published. Required fields are marked *