• About Us
  • Privacy Policy
  • Disclaimer
  • Contact Us
AimactGrow
  • Home
  • Technology
  • AI
  • SEO
  • Coding
  • Gaming
  • Cybersecurity
  • Digital marketing
No Result
View All Result
  • Home
  • Technology
  • AI
  • SEO
  • Coding
  • Gaming
  • Cybersecurity
  • Digital marketing
No Result
View All Result
AimactGrow
No Result
View All Result

Case Examine: Combining Reducing-Edge CSS Options Right into a “Course Navigation” Element

Admin by Admin
March 26, 2025
Home Coding
Share on FacebookShare on Twitter


I got here throughout this superior article navigator by Jhey Tompkins:

It solved a UX downside I used to be dealing with on a challenge, so I’ve tailored it to the wants of a web-based course — a “course navigator” if you’ll — and constructed upon it. And right now I’m going to choose it aside and present you the way it all works:

You’ll be able to see I’m imagining this as some kind of navigation that you simply may discover in a web-based studying administration system that powers a web-based course. To summarize what this part does, it:

  • hyperlinks to all course classes,
  • easily scrolls to anchored lesson headings,
  • signifies how a lot of the present lesson has been learn,
  • toggles between gentle and darkish modes, and
  • sits fastened on the backside and collapses on scroll.

Additionally, whereas not a characteristic, we received’t be utilizing JavaScript. You may assume that’s unattainable, however the spate of CSS options which have lately shipped make all of this attainable with vanilla CSS, albeit utilizing bleeding-edge methods which might be solely totally supported by Chrome on the time I’m scripting this. So, crack open the most recent model and let’s do that collectively!

The HTML

We’re taking a look at a disclosure widget (the

factor) pinned to the underside of the web page with fastened positioning. Behind it? A course lesson (or one thing of that impact) wrapped in an

with ids on the headings for same-page anchoring. Clicking on the disclosure’s

toggles the course navigation, which is wrapped in a ::details-content pseudo-element. This navigation hyperlinks to different classes but additionally scrolls to the aforementioned headings of the present lesson.

The

comprises a label (because it features as a toggle-disclosure button), the title of the present lesson, the space scrolled, and a darkish mode toggle.

With me to date?

...

Part B

...

Part C

...

Entering into place

First, we’ll place the disclosure with fastened positioning in order that it’s pinned to the underside of the web page:

particulars {
  place: fastened;
  inset: 24px; /* Use as margin */
  place-self: finish middle; /* y x */
}

Establishing CSS-only darkish mode (the brand new approach)

There are particular eventualities the place darkish mode is best for accessibility, particularly for the legibility of long-form content material, so let’s set that up.

First, the HTML. We’ve got an unpleasant checkbox enter that’s hidden due to its hidden attribute, adopted by an which’ll be a better-looking fake checkbox as soon as we’ve sprinkled on some Font Superior, adopted by a for the checkbox’s textual content label. All of that is then wrapped in an precise , which is wrapped by the

. We wrap the label’s content material in a in order that flexbox holes get utilized between all the pieces.

Functionally, though the checkbox is hidden, it toggles each time its label is clicked. And on that observe, it is likely to be a good suggestion to position an express aria-label on this label, simply to be 100% certain that display readers announce a label, since implicit labels don’t all the time get picked up.

Subsequent we have to put the correct icons in there, topic to a little bit conditional logic. Moderately than use Font Superior’s HTML lessons and need to fiddle with CSS overwrites, we’ll use Font Superior’s CSS properties with our rule logic, as follows:

If the factor is adopted by (discover the next-sibling combinator) a checked checkbox, we’ll show a checked checkbox icon in it. If it’s adopted by an unchecked checkbox, we’ll show an unchecked checkbox icon in it. It’s nonetheless the identical rule logic even should you don’t use Font Superior.

/* Copied from Font Superior’s CSS */
i::earlier than {
  font-style: regular;
  font-family: "Font Superior 6 Free";
  show: inline-block;
  width: 1.25em; /* Prevents content material shift when swapping to in a different way sized icons by making all of them have the identical width (that is equal to Font Superior’s .fa-fw class) */
}

/* If adopted by a checked checkbox... */
enter[type=checkbox]:checked + i::earlier than {
  content material: "f058";
  font-weight: 900;
}

/* If adopted by an unchecked checkbox... */
enter[type=checkbox]:not(:checked) + i::earlier than {
  content material: "f111";
  font-weight: 400;
}

We have to implement the modes on the root stage (once more, utilizing a little bit conditional logic). If the foundation :has the checked checkbox, apply color-scheme: darkish. If the foundation does :not(:has) the unchecked checkbox, then we apply color-scheme: gentle.

/* If the foundation has a checked checkbox... */
:root:has(enter[type=checkbox]:checked) {
  color-scheme: darkish;
}

/* If the foundation doesn't have a checked checkbox... */
:root:not(:has(enter[type=checkbox]:checked)) {
  color-scheme: gentle;
}

Should you toggle the checkbox, your net browser’s UI will already toggle between gentle and darkish colour schemes. Now let’s be sure that our demo does the identical factor utilizing the light-dark() CSS perform, which takes two values — the sunshine mode colour after which the darkish mode colour. You’ll be able to make the most of this perform as a substitute of any colour information sort (afterward we’ll even use it inside a conic gradient).

Within the demo I’m utilizing the identical HSL colour all through however with totally different lightness values, then flipping the lightness values based mostly on the mode:

colour: light-dark(hsl(var(--hs) 90%), hsl(var(--hs) 10%));
background: light-dark(hsl(var(--hs) 10%), hsl(var(--hs) 90%));

I don’t assume the light-dark() perform is any higher than swapping out CSS variables, however I don’t imagine it’s any worse both. Completely as much as you so far as which strategy you select.

Displaying scroll progress

Now let’s show the quantity learn as outlined by the scroll progress, first, as what I prefer to name a “progress pie” after which, second, as a plain-text share. These’ll go within the center a part of the

:

1. LessonA

What we want is to show the proportion and permit it to “rely” because the scroll place adjustments. Usually, that is squarely in JavaScript territory. However now that we are able to outline our personal customized properties, we are able to set up a variable referred to as --percentage that’s formatted as an integer that defaults to a worth of 0. This gives CSS with the context it must learn and interpolate the worth between 0 and 100, which is the utmost worth we wish to help.

So, first, we outline the variable as a customized property:

@property --percentage {
  syntax: "";
  inherits: true;
  initial-value: 0;
}

Then we outline the animation in keyframes in order that the worth of --percentage is up to date from 0 to 100:

@keyframes updatePercentage {
  to {
    --percentage: 100;
  }
}

And, lastly, we apply the animation on the foundation factor:

:root {
  animation: updatePercentage;
  animation-timeline: scroll();
  counter-reset: share var(--percentage);
}

Discover what we’re doing right here: this can be a scroll-driven animation! By setting the animation-timeline to scroll(), we’re not operating the animation based mostly on the doc’s timeline however as a substitute based mostly on the consumer’s scroll place. You’ll be able to dig deeper into scroll timelines within the CSS-Tips Almanac.

Since we’re coping with an integer, we are able to goal the ::earlier than pseudo-element and place the proportion worth within it utilizing the content material property and a little bit counter() hacking (adopted by the proportion image):

#progress-percentage::earlier than {
  content material: counter(share) "%";
  min-width: 40px; show: inline-block; /* Prevents content material shift */
}

The progress pie is simply as simple. It’s a conic gradient made up of two colours which might be positioned utilizing 0% and the scroll share! Which means that you’ll want that --percentage variable as an precise share, however you may convert it into such by multiplying it by 1% (calc(var(--percentage) * 1%))!

#progress-pie {
  aspect-ratio: 1;
  background: conic-gradient(hsl(var(--hs) 50%) calc(var(--percentage) * 1%), light-dark(hsl(var(--hs) 90%), hsl(var(--hs) 10%)) 0%);
  border-radius: 50%; /* Make it a circle */
  width: 17px; /* Similar dimensions because the icons */
}

Making a (good) course navigation

Now for the desk contents containing the nested lists of lesson sections inside them, beginning with some resets. Whereas there are extra resets within the demo and extra traces of code total, two particular resets are very important to the UX of this part.

First, right here’s an instance of how the nested lists are marked up:

  1. LessonA
    1. SectionA
    2. SectionB
    3. SectionC
  2. LessonB
  3. LessonC

Let’s reset the listing spacing in CSS:

ol {
  padding-left: 0;
  list-style-position: inside;
}

padding-left: 0 ensures that the mum or dad listing and all nested lists snap to the left aspect of the disclosure, minus any padding you may wish to add. Don’t fear in regards to the indentation of nested lists — we’ve got one thing deliberate for these. list-style-position: inside ensures that the listing markers snap to the aspect, fairly than the textual content, inflicting the markers to overflow.

After that, we slap colour: clear on the ::markers of nested

  • components since we don’t want the lesson part titles to be numbered. We’re solely utilizing nested lists for semantics, and nested numbered lists particularly as a result of a unique sort of listing marker (e.g., bullets) would trigger vertical misalignment between the course’s lesson titles and the lesson part titles.

    ol ol li::marker {
      colour: clear;
    }

    Lastly, in order that customers can extra simply traverse the present lesson, we’ll dim all listing gadgets that aren’t associated to the present lesson. It’s a type of emphasizing one thing by de-emphasizing others:

    particulars {
      /* The default colour */
      colour: light-dark(hsl(var(--hs) 90%), hsl(var(--hs) 10%));
    }
    
    /* 
  • s with out .lively that’re direct descendants of the mum or dad
      */ ol:has(ol) > li:not(.lively) { /* A much less intense colour */ colour: light-dark(hsl(var(--hs) 80%), hsl(var(--hs) 20%)); } /* Additionally */ a { colour: inherit; }
  • Yet one more factor… these anchor hyperlinks scroll customers to particular headings, proper? So, placing scroll-behavior: easy on the foundation to permits easy scrolling between them. And that percentage-read tracker that we created? Yep, that’ll work right here as nicely.

    :root {
      scroll-behavior: easy; /* Clean anchor scrolling */
      scroll-padding-top: 20px; /* A scroll offset, mainly */
    }

    Transitioning the disclosure

    Subsequent, let’s transition the opening and shutting of the ::details-content pseudo-element. By default, the

    factor snaps open and closed when clicked, however we wish a easy transition as a substitute. Geoff lately detailed how to do that in a complete set of notes in regards to the

    factor, however we’ll break it down collectively.

    First, we’ll transition from peak: 0 to peak: auto. It is a brand-new characteristic in CSS! We begin by “opting into” the characteristic on the root stage with interpolate-size: allow-keywords`:

    :root {
      interpolate-size: allow-keywords;
    }

    I like to recommend setting overflow-y: clip on particulars::details-content to forestall the content material from overflowing the disclosure because it transitions out and in:

    particulars::details-content {
      overflow-y: clip;
    }

    An alternative choice is sliding the content material out and then fading it in (and vice-versa), however you’ll must be fairly particular in regards to the transition’s setup.

    First, for the “earlier than” and “after” states, you’ll want to focus on each particulars[open] and particulars:not([open]), as a result of vaguely concentrating on particulars after which overwriting the transitioning types with particulars[open] doesn’t permit us to reverse the transition.

    After that, slap the identical transition on each however with totally different values for the transition delays in order that the fade occurs after when opening however earlier than when closing.

    Lastly, you’ll additionally have to specify which properties are transitioned. We might merely put the all key phrase in there, however that’s neither performant nor permits us to set the transition durations and delays for every property. So we’ll listing them individually as a substitute in a comma-separated listing. Discover that we’re particularly transitioning the content-visibility and utilizing the allow-discrete key phrase as a result of it’s a discrete property. that is why we opted into interpolate-size: allow-keywords earlier.

    particulars:not([open])::details-content {
      peak: 0;
      opacity: 0;
      padding: 0 42px;
      filter: blur(10px);
      border-top: 0 stable light-dark(hsl(var(--hs) 30%), hsl(var(--hs) 70%));
      transition:
        peak 300ms 300ms, 
        padding-top 300ms 300ms, 
        padding-bottom 300ms 300ms, 
        content-visibility 300ms 300ms allow-discrete, 
        filter 300ms 0ms, 
        opacity 300ms 0ms;
    }
    
    particulars[open]::details-content {
      peak: auto;
      opacity: 1;
      padding: 42px;
      filter: blur(0);
      border-top: 1px stable light-dark(hsl(var(--hs) 30%), hsl(var(--hs) 70%));
      transition: 
        peak 300ms 0ms, 
        padding-top 300ms 0ms, 
        padding-bottom 300ms 0ms, 
        content-visibility 300ms 0ms allow-discrete, 
        filter 300ms 300ms, 
        opacity 300ms 300ms;
    }

    Giving the abstract a label and icons

    Previous the present lesson’s title, share learn, and darkish mode toggle, the

    factor wants a label that helps describe what it does. I went with “Navigate course” and included an aria-label saying the identical factor in order that display readers didn’t announce all that different stuff.

    Navigate course

    As well as, the abstract will get show: flex in order that we are able to simply separate the three sections with a hole, which additionally removes the abstract’s default marker, permitting you to make use of your personal. (Once more, I’m utilizing Font Superior within the demo.)

    i::earlier than {
      width: 1.25em;
      font-style: regular;
      show: inline-block;
      font-family: "Font Superior 6 Free";
    }
    
    particulars i::earlier than {
      content material: "f0cb"; /* fa-list-ol */
    }
    
    particulars[open] i::earlier than {
      content material: "f00d"; /* fa-xmark */
    }
    
    
    /* For older Safari */
    abstract::-webkit-details-marker {
       show: none;
    }

    And eventually, should you’re pro-cursor: pointer for many interactive components, you’ll wish to apply it to the abstract and manually be sure that the checkbox’s label inherits it, because it doesn’t try this robotically.

    abstract {
      cursor: pointer;
    }
    
    label {
      cursor: inherit;
    }

    Giving the disclosure an auto-closure mechanism

    A tiny little bit of JavaScript couldn’t damage although, might it? I do know I stated this can be a no-JavaScript deal, however this one-liner will robotically shut the disclosure when the mouse leaves it:

    doc.querySelector("particulars").addEventListener("mouseleave", e => e.goal.removeAttribute("open"));

    Annoying or helpful? I’ll allow you to determine.

    Setting the popular colour scheme robotically

    Setting the popular colour scheme robotically is definitely helpful, however should you prefer to keep away from JavaScript wherever attainable, I don’t assume customers will likely be too mad for not providing this characteristic. Both approach, the next conditional snippet checks if the consumer’s most popular colour scheme is “darkish” by evaluating the related CSS media question (prefers-color-scheme: darkish) utilizing window.matchMedia and matches. If the situation is met, the checkbox will get checked, after which the CSS handles the remainder.

    if (window.matchMedia("prefers-color-scheme: darkish").matches) {
      doc.querySelector("enter[type=checkbox]").checked = true;
    }

    Recap

    This has been enjoyable! It’s such a blessing we are able to mix all of those cutting-edge CSS options, not simply into one challenge however right into a single part. To summarize, that features:

    • a course navigator that reveals the present lesson, all different classes, and easy scrolls between the totally different headings,
    • a percentage-scrolled tracker that reveals the quantity learn in plain textual content and as a conic gradient… pie chart,
    • a light-weight/dark-mode toggle (with some non-obligatory JavaScript that detects the popular colour scheme), and it’s
    • all packed right into a single, floating, animated, native disclosure part.

    The newer CSS options we lined within the course of:

    • Scroll-driven animations
    • interpolate-size: allow-keywords for transitioning between 0 and auto
    • easy scrolling by means of scroll-behavior: easy
    • darkish mode magic utilizing the light-dark() perform
    • a progress chart made with a conic-gradient()
    • styling the ::details-content pseudo-element
    • animating the
      factor

    Due to Jhey for the inspiration! Should you’re not following Jhey on Bluesky or X, you’re lacking out. You may as well see his work on CodePen, a few of which he has talked about proper right here on CSS-Tips.

  • Tags: CaseCombiningComponentCSSCuttingEdgeFeaturesNavigationStudy
    Admin

    Admin

    Next Post
    Open Supply devs say AI crawlers dominate visitors, forcing blocks on whole nations

    Open Supply devs say AI crawlers dominate visitors, forcing blocks on whole nations

    Leave a Reply Cancel reply

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

    Recommended.

    Indian tech startup funding surged 23% YoY to $7.4B in 2024, with the variety of offers up 27% YoY and newly based startups greater than doubling (Moneycontrol)

    Indian tech startup funding surged 23% YoY to $7.4B in 2024, with the variety of offers up 27% YoY and newly based startups greater than doubling (Moneycontrol)

    April 4, 2025
    The Love-Hate Actuality of AI Video Mills

    The Love-Hate Actuality of AI Video Mills

    April 30, 2025

    Trending.

    Industrial-strength April Patch Tuesday covers 135 CVEs – Sophos Information

    Industrial-strength April Patch Tuesday covers 135 CVEs – Sophos Information

    April 10, 2025
    Expedition 33 Guides, Codex, and Construct Planner

    Expedition 33 Guides, Codex, and Construct Planner

    April 26, 2025
    How you can open the Antechamber and all lever places in Blue Prince

    How you can open the Antechamber and all lever places in Blue Prince

    April 14, 2025
    Important SAP Exploit, AI-Powered Phishing, Main Breaches, New CVEs & Extra

    Important SAP Exploit, AI-Powered Phishing, Main Breaches, New CVEs & Extra

    April 28, 2025
    Wormable AirPlay Flaws Allow Zero-Click on RCE on Apple Units by way of Public Wi-Fi

    Wormable AirPlay Flaws Allow Zero-Click on RCE on Apple Units by way of Public Wi-Fi

    May 5, 2025

    AimactGrow

    Welcome to AimactGrow, your ultimate source for all things technology! Our mission is to provide insightful, up-to-date content on the latest advancements in technology, coding, gaming, digital marketing, SEO, cybersecurity, and artificial intelligence (AI).

    Categories

    • AI
    • Coding
    • Cybersecurity
    • Digital marketing
    • Gaming
    • SEO
    • Technology

    Recent News

    Yoast AI Optimize now out there for Basic Editor • Yoast

    Replace on Yoast AI Optimize for Traditional Editor  • Yoast

    June 18, 2025
    You’ll at all times keep in mind this because the day you lastly caught FamousSparrow

    You’ll at all times keep in mind this because the day you lastly caught FamousSparrow

    June 18, 2025
    • About Us
    • Privacy Policy
    • Disclaimer
    • Contact Us

    © 2025 https://blog.aimactgrow.com/ - All Rights Reserved

    No Result
    View All Result
    • Home
    • Technology
    • AI
    • SEO
    • Coding
    • Gaming
    • Cybersecurity
    • Digital marketing

    © 2025 https://blog.aimactgrow.com/ - All Rights Reserved