Tag: Menu

Semantic menu context

Scott digs into the history of the <menu> element. He traced it as far back as HTML 2 (!) in a 1994 changelog. The vibe then, it seems, was to mark up a list. I would suspect the intention is much like <nav> is today, but I really don’t know.

Short story: HTML 4 deprecated it, HTML 5 revived it—this time as a “group of commands”—and then HTML 5.2 deprecated it again. Kind of a bummer since it has some clear use cases.

So, it’s been quite the roller coaster for ol’ <menu>! There never seems to be any easy wins for HTML evolution. As of now, it’s in “don’t bother” territory:

I really wrote this post as a sort of counter point to the often uttered phrase “use semantic HTML and you get accessibility for free!” That statement, on its surface, is largely true. And you should use semantic HTML wherever its use is appropriate. <menu>, unfortunately, doesn’t really give us all that much, even though it has clearly defined semantics. Its intended semantics and what we actually need in reality are better served by either just using the more robust <ul> element, or creating your own role=toolbarmenubar, etc.. Using this semantic element, for semantics sake, is just that.

To Shared LinkPermalink on CSS-Tricks

The post Semantic menu context appeared first on CSS-Tricks. You can support CSS-Tricks by being an MVP Supporter.


, ,

Yet Another Mobile Context Menu With No Indication it Can Scroll

Remember Tyler Hall’s personal story of a UX moment where the popup sharing context menu on iOS had no visible indication that the content inside was scrollable? The thing his mom wanted to do seemed impossible iOS isn’t alone here — Terence Eden documents essentially the same problem on Android:

I tried sharing a website using Google Chrome for Android. I hit the share button, and a panel popped-up from the bottom of the screen.

Hmmm. It didn’t have the share destination that I wanted. It was early in the morning – when I’m not at my cognitive best – and I was stumped. There is nothing on this screen – other than the icons – to tell me how I can interact with it. There’s no scrollbar, no handle, no “more” icon, nothing.

I would think even just fairly subtle “scroll shadows” would go a long way in both cases, but some serious user testing should be in order here.

Android menu with no indication of scrolling potential.

iOS menu with no indication of scrolling potential.

The post Yet Another Mobile Context Menu With No Indication it Can Scroll appeared first on CSS-Tricks. You can support CSS-Tricks by being an MVP Supporter.


, , , , ,

Are Custom Properties a “Menu of What Will Change”?

PPK laid out an interesting situation in “Two options for using custom properties” where he and Stefan Judis had two different approaches for doing the same thing with custom properties. In one approach, hover and focus styles for a link are handled with two different custom properties, one for each state. In the other approach, a single custom property is used.

Two custom properties:

.component1 {   --linkcolor: red;   --hovercolor: blue; }  .component2 {   --linkcolor: purple;   --hovercolor: cyan; }  a {   color: var(--linkcolor); }  a:hover,a:focus {   color: var(--hovercolor) }

One custom property:

.component1 a {   --componentcolor: red; }  .component1 :is(a:hover,a:focus) {   --componentcolor: blue; } 	 .component2 a {   --componentcolor: purple; }  .component2 :is(a:hover,a:focus) {   --componentcolor: cyan; } 	 a {   color: var(--componentcolor)		 }

There is something more natural feeling about using two properties, like it’s very explicit about what a particular custom property is meant to do. But there is a lot of elegance to using one custom property. Not just for the sake of being one-less custom property, but that the custom property is 1-to-1 matched with a single property.

Taking this a bit further, you could set up a single ruleset with one custom property per property, giving it a sort of menu for what things will change. To that PPK says:

Now you essentially found a definition file. Not only do you see the component’s default styles, you also see what might change and what will not.

That is to say, you’d use a custom property for anything you intend to change, and anything you don’t, you wouldn’t. That’s certainly an interesting approach that I wouldn’t blame anyone for trying.

.lil-grid {   /* will change */   --padding: 1rem;   padding: var(--padding);   --grid-template-columns: 1fr 1fr 1fr;   grid-columns: var(--grid-template-columns);    /* won't change */   border: 1px solid #ccc;   gap: 1rem; }

My hesitation with this is that it’s, at best, a hint at what will and won’t change. For example, I can still change things even though they aren’t set in a custom property. Later, I could do:

.lil-grid.two-up {   grid-columns: 1fr 1fr; }

That wipes out the custom property usage. Similarly, I could never change the value of --grid-template-columns, meaning it looks like it changes under different circumstances, but never does.

Likewise, I could do:

.lil-grid.thick {   border-width: 3px; }

…and even though my original component ruleset implies that the border width doesn’t change, it does with a modifier class.

So, in order to make an approach like that work, you treat it like a convention that you stick to, like a generic coding standard. I’d worry it becomes a pain in the butt, though. For any declaration you decide to change, you gotta go back and refactor it to either be or not be a custom property.

This makes me think about the “implicit styling API” that is HTML and CSS. We’ve already got a styling API in browsers. HTML is turned into the DOM in the browser, and we style the DOM with CSS. Select things, style them.

Maybe we don’t need a menu for what you can and cannot style because that’s what the DOM and CSS already are. That’s not to say a well-crafted set of custom properties can’t be a part of that, but they don’t need to represent hardline rules on what changes and what doesn’t.

Speaking of implicit styling APIs, Jim Nielsen writes in “Shadow DOM and Its Effect on the Unofficial Styling API”:

[…] the shadow DOM breaks the self-documenting style API we’ve had on the web for years.

What style API? If you want to style an element on screen, you open the dev tools, look at the DOM, find the element you want, figure out the right selector to target that element, write your selector and styles, and you’re done.

That’s pretty remarkable when you stop and think about it.

I suppose that’s my biggest beef with web components. I don’t dislike the Shadow DOM; in fact, it’s probably my favorite aspect of web components. I just dislike how I have to invent a styling API for them (à la custom properties that wiggle inside, or ::part) rather than use the styling API that has served us well forever: DOM + CSS.

The post Are Custom Properties a “Menu of What Will Change”? appeared first on CSS-Tricks.

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


, , ,

In Praise of the Unambiguous Click Menu

I still remember my excitement when I learned how to build a hover-triggered submenu with just CSS. (It was probably after reading this 2003 article from A List Apart.) At the time, it was a true CSS trick. Seriously. Wild times.

That went a little something like this:

<ul class="my-menu">   <li>     <a href="page-a.html">Page A</a>     <ul>       <li><a href="page-b.html">Page B</a></li>       <li><a href="page-c.html">Page C</a></li>       <li><a href="page-d.html">Page D</a></li>     </ul>   </li>   <!-- etc... --> </ul>
/* Position submenus relative to parent list item */ .my-menu li {   position: relative; }  .my-menu ul {   /* Hide my submenus by default */   display: none;   /* Position submenus, when open */   position: absolute;   left: 0;   top: 100%; }  /* Look, Ma! No onclick handler! */ .my-menu li:hover > ul {   display: block; }

These days, we can improve the accessibility of CSS-only menus with a newer trick! Menus can open and close when navigating them with a keyboard, thanks to :focus-within.

/* No IE11 support */ .my-menu li:focus-within > ul {   display: block; }

Try using both your mouse and the TAB key to move through the demo.

But times have changed from when I first learned these tricks, and so have I. Since then, I’ve built a bunch of websites and learned a lot more about usability, accessibility, and content strategy. Now, I find hover-triggered menus lacking on all those fronts. So, a few years ago, I quit building hover-triggered submenus and switched to click-triggered submenus. (From here, I’ll just call them “hover menus” and “click menus.”)

I think you should should stop building hover menus too. I’m here to tell you why.

Hover menus are inconsistent

Take a look at this real menu from a site I built:

Simple enough, right? The arrow icons show us there are submenus for each item except “Home.” But if those submenus appear on hover, there are at least four ways the menu might work, and you’ve probably experienced all four of them.

  1. The top “parent” menu item links to a page and each submenu item links to another page. For the example above, “Services” would be a unique page and so would every link in the “Services” submenu.

But somewhere along the way, a second very common pattern arose.

  1. The parent item has href="#"— or even no href at all 😱and the only functional links are in the submenus. In our example, “Services” is still a link, but nothing happens when you click it.

This inconsistency — is the parent item a link or not? — leads to lots of confusion when I watch people use websites. Some people skip right past helpful top-level pages, assuming those items aren’t links. Yet others assume the top-level links are pages and try to click them.

This leads to the third and fourth not-so-great patterns you’ll encounter. My guess is that these evolved from attempts to compensate for the confusion caused by the first two setups.

  1. The parent item and first submenu item link to the same page. Making matters worse, the parent item and first submenu links having different link text violates a WCAG 2.1 Level AA accessibility standard.
  2. The parent item links to a page containing useless fluff content or only the links in the submenu. The page itself serves no real purpose for anyone visiting it.

These last two configurations waste time for people who do know the parent items are links with redundant or useless content.

Here’s a diagram showing all four possible hover menu setups.

Image of a white menu with four menu items going from left to right. The menu is against a gradient background that goes from a burnt orange to a deep purple horizontally. Each menu item corresponds to one of the usability issues that were described.
When first seeing a hover menu, a visitor can reasonably wonder which of these four ways the menu might work.

Visitors are reasonably confused by hover menus

No matter how we implement hover menus, our visitors can reasonably wonder:

  1. Can I click the parent items?
  2. Will the parent item be a link to the same page as the first submenu link?
  3. Even if the parent item is a unique link, is it worth my time to view?

That leaves us with no good options. It makes it impossible to satisfy Jakob’s law of usability that “users prefer your site to work the same way as all the other sites they already know.” There is no standard implementation when it comes to hover menus, so we need to do something different to provide a consistent user experience.

What about “Split Button” menus?

Probably the least common type of menu I see uses a “split button” design where the parent item is a link and a separate drop-down icon opens and closes the menu. The Twenty Fifteen default WordPress theme uses that pattern. Because it’s so uncommon, I find that visitors often overlook the top-level page link, and research suggests that users don’t perceive a label and icon as being separately clickable.

A “split button” menu item from the Twenty Fifteen WordPress Theme
Until someone hovers or focuses the arrow button, they probably won’t guess it’s independent of the link.

So, what’s the better option? Enter the click-triggered submenu!

Click menus to the rescue

Instead of relying on the hover interaction or some other “creative” (and confusing) solution, let’s build menus where parent items are buttons that show and hide submenus when clicked. This instantly solves the hover menu problem because click menus work unambiguously.

  • Site visitors must click the parent item to view its submenu.
  • All links are contained in submenus except for top-level items that have no submenu (e.g. “Home”). We’ll deal with what happens to those top-level pages in a moment.

When you think about it, click menus are actually what we expect already in most other contexts:

  • Using a touch device? Hover isn’t really a thing there.
  • Using an application menu (e.g. File, Edit, etc.)? Those almost never appear on hover!
  • Using anything other than a mouse? Pressing ENTER or activating a link with any type of switch control is more equivalent to clicking than :focus is equivalent to :hover.

Regardless of your device or input mode, a “click” is a more universal and solid interaction. Let’s use it to make our website menus awesome!

Switching to click menus

My gut feeling says that a lot of sites have recently switched to click menus. Join the party! As more and more sites make the change, people will again develop simple and useful expectations of “how websites work” (thereby satisfying Jakob’s law).

When you first make this change, it’s true that some visitors might still expect hover menus. They may even say they prefer them if you ask. What I can tell you from watching people use click menus, though, is that everyone figures it out quickly and adjusts.

And don’t just take my word for it! The U.S. Web Design System’s (USWDS) navigation patterns use click menus. Here’s what they have to say:

Avoid using hover to expand dropdown lists. Hover is difficult for some users and won’t work on touch screens. Dropdowns should expand on click or with keyboard navigation.

Bootstrap uses click menus, too, for these same reasons:

What it really boils down to is user intent. The purpose of a hover state is to indicate something is clickable (underlined text)… The purpose of a click is to actually do something, to take an explicit action. Opening a dropdown is an explicit action and should only happen on click.

From the same article, there’s this great nugget:

The caret in a dropdown link is the equivalent of underlining a link: it provides some affordance for what will happen when you click this element. Don’t mistake that for providing enough information to pop the dropdown on hover though.

So it’s not like we’re exploring uncharted territory here. And, the UK.gov design system has another good reminder: Maybe you don’t even need submenus at all! Their menus are just a list of links, using on-page grids of links and accordions to help visitors navigate. Heck, you won’t find submenus on CSS-Tricks either!

Click menus come with bonus benefits!

The more you work with click menus, the more benefits you discover:

  • You decide whether you need a category/overview/landing page… or not! Instead of forcing content to match a menu’s structure with links that are parents of other links, your content strategy and information architecture dictates what types of pages you need and how they are labeled. If an overview of your services is helpful for your visitors, put “Services Overview” or “All Services” as the first item in your “Services” submenu.
  • Submenus stay open until they are closed. Hover menus have a nasty way of disappearing when people bump their cursors or even just try to click a submenu link. This is especially the case for submenus that “fly out” rather than below the parent item. The persistence of click menus makes for a more “solid” experience so users trust the interface and don’t get frustrated.
  • The persistent submenu behavior is even more crucial for megamenus. When visitors need more time to take in the submenu contents, they can’t afford to have the menu close unexpectedly.
  • The JavaScript is the same for “mobile” and “desktop” menus. Whether the menu is hidden behind a hamburger or visible on mobile, the interaction is always the same. I only need to change my CSS to make a responsive click menu.

Building click menus

When I set out to build my own accessible click menu script, I found there wasn’t a single standard for how to do it. My own thoughts and code were most heavily influenced by:

The key takeaways from my research on implementation:

  • The element you click to show the submenu should be a <button> since it doesn’t link to a page.
  • Use aria-expanded (on the <button>!) to communicate the submenu’s open and closed states.
  • Use display: none or visibility: hidden so that keyboard users can’t get to submenus when they are closed.
  • aria-controls is poop, but you might as well add it.
  • Do not use role="menu" (and the whole ARIA menu pattern) or aria-haspopup. Those feel related but they aren’t for building navigation menus.
  • Close an open submenu when:
    • Another submenu opens
    • The user clicks outside the menu
    • The user presses the ESC key when focus is inside an open submenu. (Not all users expect this, but I think it’s a nice touch.)

Since click menus require JavaScript, we should consider how this menu can be progressively enhanced in case JavaScript fails for any reason. Our classic hover CSS trick is still good for something after all!

I start building my click menu as a CSS-only hover menu that uses li:hover > ul and li:focus-within > ul to show the submenus. Then, I use JavaScript to create the <button> elements, set the aria attributes, and add the event handlers. This means the menu still mostly works without JavaScript and plays nicely with link-only menus built in WordPress, my CMS of choice.

You can check out the script I use below, but I’ll be the first to admit there are probably better ones. What’s important is that you test it with real users… and stop using hover menus. 😃

The post In Praise of the Unambiguous Click Menu appeared first on CSS-Tricks.

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


, , ,

How We Improved the Accessibility of Our Single Page App Menu

I recently started working on a Progressive Web App (PWA) for a client with my team. We’re using React with client-side routing via React Router, and one of the first elements that we made was the main menu. Menus are a key component of any site or app. That’s really how folks get around, so making it accessible was a super high priority for the team.

But in the process, we learned that making an accessible main menu in a PWA isn’t as obvious as it might sound. I thought I’d share some of those lessons with you and how we overcame them.

As far as requirements go, we wanted a menu that users could not only navigate using a mouse, but using a keyboard as well, the acceptance criteria being that a user should be able to tab through the top-level menu items, and the sub-menu items that would otherwise only be visible if a user with a mouse hovered over a top-level menu item. And, of course, we wanted a focus ring to follow the elements that have focus.

The first thing we had to do was update the existing CSS that was set up to reveal a sub-menu when a top-level menu item is hovered. We were previously using the visibility property, changing between visible and hidden on the parent container’s hovered state. This works fine for mouse users, but for keyboard users, focus doesn’t automatically move to an element that is set to visibility: hidden (the same applies for elements that are given display: none). So we removed the visibility property, and instead used a very large negative position value:

.menu-item {   position: relative; }  .sub-menu {   position: absolute   left: -100000px; /* Kicking off  the page instead of hiding visiblity */ }  .menu-item:hover .sub-menu {   left: 0; }

This works perfectly fine for mouse users. But for keyboard users, the sub menu still wasn’t visible even though focus was within that sub menu! In order to make the sub-menu visible when an element within it has focus, we needed to make use of :focus and :focus-within on the parent container:

.menu-item {   position: relative; }  .sub-menu {   position: absolute   left: -100000px; }  .menu-item:hover .sub-menu, .menu-item:focus .sub-menu, .menu-item:focus-within .sub-menu {   left: 0; }

This updated code allows the the sub-menus to appear as each of the links within that menu gets focus. As soon as focus moves to the next sub menu, the first one hides, and the second becomes visible. Perfect! We considered this task complete, so a pull request was created and it was merged into the main branch.

But then we used the menu ourselves the next day in staging to create another page and ran into a problem. Upon selecting a menu item—regardless of whether it’s a click or a tab—the menu itself wouldn’t hide. Mouse users would have to click off to the side in some white space to clear the focus, and keyboard users were completely stuck! They couldn’t hit the esc key to clear focus, nor any other key combination. Instead, keyboard users would have to press the tab key enough times to move the focus through the menu and onto another element that didn’t cause a large drop down to obscure their view.

The reason the menu would stay visible is because the selected menu item retained focus. Client-side routing in a Single Page Application (SPA) means that only a part of the page will update; there isn’t a full page reload.

There was another issue we noticed: it was difficult for a keyboard user to use our “Jump to Content” link. Web users typically expect that pressing the tab key once will highlight a “Jump to Content” link, but our menu implementation broke that. We had to come up with a pattern to effectively replicate the “focus clearing” that browsers would otherwise give us for free on a full page reload.

The first option we tried was the easiest: Add an onClick prop to React Router’s Link component, calling document.activeElement.blur() when a link in the menu is selected:

const Menu = () => {   const clearFocus = () => {     document.activeElement.blur();   }    return (     <ul className="menu">       <li className="menu-item">         <Link to="/" onClick={clearFocus}>Home</Link>       </li>       <li className="menu-item">         <Link to="/products" onClick={clearFocus}>Products</Link>         <ul className="sub-menu">           <li>             <Link to="/products/tops" onClick={clearFocus}>Tops</Link>           </li>           <li>             <Link to="/products/bottoms" onClick={clearFocus}>Bottoms</Link>           </li>           <li>             <Link to="/products/accessories" onClick={clearFocus}>Accessories</Link>           </li>         </ul>       </li>     </ul>   ); }

This approach worked well for “closing” the menu after an item is clicked. However, if a keyboard user pressed the tab key after selecting one of the menu links, then the next link would become focused. As mentioned earlier, pressing the tab key after a navigation event would ideally focus on the “Jump to Content” link first.

At this point, we knew we were going to have to programmatically force focus to another element, preferably one that’s high up in the DOM. That way, when a user starts tabbing after a navigation event, they’ll arrive at or near the top of the page, similiar to a full page reload, making it much easier to access the jump link.

We initially tried to force focus on the <body> element itself, but this didn’t work as the body isn’t something the user can interact with. There wasn’t a way for it to receive focus.

The next idea was to force focus on the logo in the header, as this itself is just a link back to the home page and can receive focus. However, in this particular case, the logo was below the “Jump To Content” link in the DOM, which means that a user would have to shift + tab to get to it. No good.

We finally decided that we had to render an interact-able element, for example, an anchor element, in the DOM, at a point that’s above than the “Jump to Content” link. This new anchor element would be styled so that it’s invisible and that users are unable to focus on it using “normal” web interactions (i.e. it’s taken out of the normal tab flow). When a user selects a menu item, focus would be programmatically forced to this new anchor element, which means that pressing tab again would focus directly on the “Jump to Content” link. It also meant that the sub-menu would immediately hide itself once a menu item is selected.

const App = () => {   const focusResetRef = React.useRef();    const handleResetFocus = () => {     focusResetRef.current.focus();   };    return (     <Fragment>       <a         ref={focusResetRef}         href="javascript:void(0)"         tabIndex="-1"         style={{ position: "fixed", top: "-10000px" }}         aria-hidden       >Focus Reset</a>       <a href="#main" className="jump-to-content-a11y-styles">Jump To Content</a>       <Menu onSelectMenuItem={handleResetFocus} />       ...     </Fragment>   ) }

Some notes of this new “Focus Reset” anchor element:

  • href is set to javascript:void(0) so that if a user manages to interact with the element, nothing actually happens. For example, if a user presses the return key immediately after selecting a menu item, that will trigger the interaction. In that instance, we don’t want the page to do anything, or the URL to change.
  • tabIndex is set to -1 so that a user can’t “normally” move focus to this element. It also means that the first time a user presses the tab key upon loading a page, this element won’t be focused, but the “Jump To Content” link instead.
  • style simply moves the element out of the viewport. Setting to position: fixed ensures it’s taken out of the document flow, so there isn’t any vertical space allocated to the element
  • aria-hidden tells screen readers that this element isn’t important, so don’t announce it to users

But we figured we could improve this even further! Let’s imagine we have a mega menu, and the menu doesn’t hide automatically when a mouse user clicks a link. That’s going to cause frustration. A user will have to precisely move their mouse to a section of the page that doesn’t contain the menu in order to clear the :hover state, and therefore allow the menu to close.

What we need is to “force clear” the hover state. We can do that with the help of React and a clearHover class:

// Menu.jsx const Menu = (props) => {   const { onSelectMenuItem } = props;   const [clearHover, setClearHover] = React.useState(false);    const closeMenu= () => {     onSelectMenuItem();     setClearHover(true);   }    React.useEffect(() => {     let timeout;     if (clearHover) {       timeout = setTimeout(() => {         setClearHover(false);       }, 0); // Adjust this timeout to suit the applications' needs     }     return () => clearTimeout(timeout);   }, [clearHover]);    return (     <ul className={`menu $  {clearHover ? "clearHover" : ""}`}>       <li className="menu-item">         <Link to="/" onClick={closeMenu}>Home</Link>       </li>       <li className="menu-item">         <Link to="/products" onClick={closeMenu}>Products</Link>         <ul className="sub-menu">           {/* Sub Menu Items */}         </ul>       </li>     </ul>   ); }

This updated code hides the menu immediately when a menu item is clicked. It also hides immediately when a keyboard user selects a menu item. Pressing the tab key after selecting a navigation link moves the focus to the “Jump to Content” link.

At this point, our team had updated the menu component to a point where we were super happy. Both keyboard and mouse users get a consistent experience, and that experience follows what a browser does by default for a full page reload.

Our actual implementation is slightly different than the example here so we could use the pattern on other projects. We put it into a React Context, with the Provider set to wrap the Header component, and the Focus Reset element being automatically added just before the Provider’s children. That way, the element is placed before the “Jump to Content” link in the DOM hierarchy. It also allows us to access the focus reset function with a simple hook, instead of having to prop drill it.

We have created a Code Sandbox that allows you to play with the three different solutions we covered here. You’ll definitely see the pain points of the earlier implementation, and then see how much better the end result feels!

We would love to hear feedback on this implementation! We think it’s going to work well, but it hasn’t been released to in the wild yet, so we don’t have definitive data or user feedback. We’re certainly not a11y experts, just doing our best with what we do know, and are very open and willing to learn more on the topic.

The post How We Improved the Accessibility of Our Single Page App Menu appeared first on CSS-Tricks.

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


, , , ,

Menu Reveal By Page Rotate Animation

There are many different approaches to menus on websites. Some menus are persistent, always in view and display all the options. Other menus are hidden by design and need to be opened to view the options. And there are even additional approaches on how hidden menus reveal their menu items. Some fly out and overlap the content, some push the content away, and others will do some sort of full-screen deal.

Whatever the approach, they all have their pros and cons and the right one depends on the situation where it’s being used. Frankly, I tend to like fly-out menus in general. Not for all cases, of course. But when I’m looking for a menu that is stingy on real estate and easy to access, they’re hard to beat.

What I don’t like about them is how often they conflict with the content of the page. A fly-out menu, at best, obscures the content and, at worst, removes it completely from the UI.

I tried taking another approach. It has the persistence and availability of a fixed position as well as the space-saving attributes of a hidden menu that flies out, only without removing the user from the current content of the page.

Here’s how I made it.

The toggle

We’re building a menu that has two states — open and closed — and it toggles between the two. This is where the Checkbox Hack comes into play. It’s perfect because a checkbox has two common interactive states — checked and unchecked (there’s also the indeterminate) — that can be used to trigger those states.

The checkbox is hidden and placed under the menu icon with CSS, so the user never sees it even though they interact with it. Checking the box (or, ahem, the menu icon) reveals the menu. Unchecking it hides it. Simple as that. We don’t even need JavaScript to do the lifting!

Of course, the Checkbox Hack isn’t the only way to do this, and if you want to toggle a class to open and close the menu with JavaScript, that’s absolutely fine.

It’s important the checkbox precedes the main content in the source code, because the :checked selector we’re going to ultimately write to make this work needs to use a sibling selector. If that’ll cause layout concerns for you, use Grid or Flexbox for your layouts as they are source order independent, like how I used its advantage for counting in CSS.

 The checkbox’s default style (added by the browser) is stripped out, using the appearance CSS property, before adding its pseudo element with the menu icon so that the user doesn’t see the square of the checkbox.

First, the basic markup:

<input type="checkbox">  <div id="menu">   <!--menu options--> </div> <div id="page">   <!--main content--> </div>

…and the baseline CSS for the Checkbox Hack and menu icon:

/* Hide checkbox and reset styles */ input[type="checkbox"] {   appearance: initial; /* removes the square box */   border: 0; margin: 0; outline: none; /* removes default margin, border and outline */   width: 30px; height: 30px; /* sets the menu icon dimensions */   z-index: 1;  /* makes sure it stacks on top */ }  
 /* Menu icon */ input::after {   content: "55";   display: block;    font: 25pt/30px "georgia";    text-indent: 10px;   width: 100%; height: 100%; }  
 /* Page content container */ #page {   background: url("earbuds.jpg") #ebebeb center/cover;   width: 100%; height: 100%; }

I threw in the styles for the #page content as well, which is going to be a full size background image.

The transition

Two things happen when the menu control is clicked. First, the menu icon changes to an × mark, symbolizing that it can be clicked to close the menu. So, we select the ::after pseudo element of checkbox input when the input is in a :checked state:

input:checked::after {   content: "d7"; /* changes to × mark */   color: #ebebeb; }

Second, the main content (our “earbuds” image) transforms, revealing the menu underneath. It moves to the right, rotates and scales down, and its left side corners get angular. This is to give the appearance of the content getting pushed back, like a door that swings open. 

input:checked ~ #page {    clip-path: polygon(0 8%, 100% 0, 100% 100%, 0 92%);   transform: translateX(40%) rotateY(10deg) scale(0.8);    transform-origin: right center;    transition: all .3s linear; } 

I used clip-path to change the corners of the image.

Since we’re applying a transition on the transformations, we need an initial clip-path value on the #page so there’s something to transition from. We’ll also drop a transition on #page while we’re at it because that will allow it to close as smoothly as it opens.

#page {   background: url("earbuds.jpeg") #ebebeb center/cover;    clip-path: polygon(0 0, 100% 0, 100% 100%, 0 100%);   transition: all .3s linear;   width: 100%; height: 100%; }

We’re basically done with the core design and code. When the checkbox is unchecked (by clicking the × mark) the transformation on the earbud image will automatically be undone and it’ll be brought back to the front and centre. 

A sprinkle of JavaScript

Even though we have what we’re looking for, there’s still one more thing that would give this a nice boost in the UX department: close the menu when clicking (or tapping) the #page element. That way, the user doesn’t need to look for or even use the × mark to get back to the content.

Since this is merely an additional way to hide the menu, we can use JavaScript. And if JavaScript is disabled for some reason? No big deal. It’s just an enhancement that doesn’t prevent the menu from working without it.

document.querySelector("#page").addEventListener('click', (e, checkbox = document.querySelector('input')) => {    if (checkbox.checked) { checkbox.checked = false; e.stopPropagation(); } });

What this three-liner does is add a click event handler over the #page element that un-checks the checkbox if the checkbox is in a :checked state, which closes the menu.

We’ve been looking at a demo made for a vertical/portrait design, but works just as well at larger landscape screen sizes, depending on the content we’re working with.

This is just one approach or take on the typical fly-out menu. Animation opens up lots of possibilities and there are probably dozens of other ideas you might have in mind. In fact, I’d love to hear (or better yet, see) them, so please share!

The post Menu Reveal By Page Rotate Animation appeared first on CSS-Tricks.

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


, , , ,

Line-Animated Hamburger Menu

This kind of SVG + CSS animation trickery is catnip to me. Mikael Ainalem shares how to draw a hamburger icon (the “three lines” thing you’re well familiar with), but then animate it in a way that is surprising and fun by controlling the SVG properties in CSS.

The trick is that the top and bottom lines aren’t just a straight <line /> but a <path /> that curves up, down, and around forming the cross. You can only see part of the line (making it appear straight at first) because the stroke-dasharray only reveals part of the line. Then, by animating both the stroke-dasharray and stroke-dashoffset, the ✕ is formed.

Direct Link to ArticlePermalink

The post Line-Animated Hamburger Menu appeared first on CSS-Tricks.


, ,