Tag: Page

Optimizing CSS for faster page loads

A straightforward post with some perf data from Tomas Pustelnik. It’s a good reminder that CSS is a crucial part of thinking web performance, and for a huge reason:

Any time [the browser] encounters any external resource (CSS, JS, images, etc.) it will assign it a download priority and initiate its download. Priorities are important because some resources are critical to render a page (eg. main stylesheet and JS files) while others may be less important (like images or stylesheets for other media types).

In the case of CSS, this priority is usually high because stylesheets are necessary to create CSSOM (CSS Object Model). To render a webpage browser has to construct both DOM and CSSOM.

That’s why CSS is often referred to as a “blocking” resource. That’s desirable to some degree: we wouldn’t want to see flash-of-unstyled-websites. But we get real perf gains when we make CSS smaller because it’s quicker to download, parse, and apply.

Aside from the techniques in the post, I’m sure advocates of atomic/all-utility CSS would love it pointed out that the stylesheets from those approaches are generally way smaller, and thus more performant. CSS-in-JS approaches will sometimes bundle styles into scripts so, to be fair, you get a little perf gain at the top by not loading the CSS there, but a perf loss from increasing the JavaScript bundle size in the process. (I haven’t seen a study with a fair comparison though, so I don’t know if it’s a wash or what.)

Direct Link to ArticlePermalink


The post Optimizing CSS for faster page loads appeared first on CSS-Tricks.

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

CSS-Tricks

, , ,

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.

CSS-Tricks

, , , ,
[Top]

Memorize Scroll Position Across Page Loads

Hakim El Hattab tweeted a really nice little UX enhancement for a static site that includes a scrollable sidebar of navigation.

The trick is to throw the scroll position into localStorage right before the page is exited, and when loaded, grab that value and scroll to it. I’ll retype it from the tweet…

let sidebar = document.querySelector(".sidebar");  let top = localStorage.getItem("sidebar-scroll"); if (top !== null) {   sidebar.scrollTop = parseInt(top, 10); }  window.addEventListener("beforeunload", () => {   localStorage.setItem("sidebar-scroll", sidebar.scrollTop); });

What is surprising is that you don’t get a flash-of-wrong-scroll-position. I wonder why? Maybe it has to do with fancy paint holding stuff browsers are doing now? Not sure.

The post Memorize Scroll Position Across Page Loads appeared first on CSS-Tricks.

CSS-Tricks

, , , , ,
[Top]

My Flywheel Landing Page

Flywheel is my WordPress hosting partner here. I use Local every day for my WordPress local development environment and use their hosting for all my WordPress sites as part of my whole flow, so I’m glad they aren’t just a sponsor but a product I use and like.

Last November some of their crew came out and shot some photos and video with me, which was cool and fun and made me feel famous lolll.

They ultimately built a landing page from it, which is super well done!

Just look at me being all famous.

Check out some photos that Kimberly Bailey took while the gang was here.

And the video!

Anyway feel free to check out that landing page and if your company is headed to make a WordPress hosting decision soon, might as well use my referral link 😉

The post My Flywheel Landing Page appeared first on CSS-Tricks.

CSS-Tricks

, ,
[Top]

How to Get All Custom Properties on a Page in JavaScript

We can use JavaScript to get the value of a CSS custom property. Robin wrote up a detailed explanation about this in Get a CSS Custom Property Value with JavaScript. To review, let’s say we’ve declared a single custom property on the HTML element:

html {   --color-accent: #00eb9b; }

In JavaScript, we can access the value with getComputedStyle and getPropertyValue:

const colorAccent = getComputedStyle(document.documentElement)   .getPropertyValue('--color-accent'); // #00eb9b

Perfect. Now we have access to our accent color in JavaScript. You know what’s cool? If we change that color in CSS, it updates in JavaScript as well! Handy.

What happens, though, when it’s not just one property we need access to in JavaScript, but a whole bunch of them?

html {   --color-accent: #00eb9b;   --color-accent-secondary: #9db4ff;   --color-accent-tertiary: #f2c0ea;   --color-text: #292929;   --color-divider: #d7d7d7; }

We end up with JavaScript that looks like this:

const colorAccent = getComputedStyle(document.documentElement).getPropertyValue('--color-accent'); // #00eb9b const colorAccentSecondary = getComputedStyle(document.documentElement).getPropertyValue('--color-accent-secondary'); // #9db4ff const colorAccentTertiary = getComputedStyle(document.documentElement).getPropertyValue('--color-accent-tertiary'); // #f2c0ea const colorText = getComputedStyle(document.documentElement).getPropertyValue('--color-text'); // #292929 const colorDivider = getComputedStyle(document.documentElement).getPropertyValue('--color-text'); // #d7d7d7

We’re repeating ourselves a lot. We could shorten each one of these lines by abstracting the common tasks to a function.

const getCSSProp = (element, propName) => getComputedStyle(element).getPropertyValue(propName); const colorAccent = getCSSProp(document.documentElement, '--color-accent'); // #00eb9b // repeat for each custom property...

That helps reduce code repetition, but we still have a less-than-ideal situation. Every time we add a custom property in CSS, we have to write another line of JavaScript to access it. This can and does work fine if we only have a few custom properties. I’ve used this setup on production projects before. But, it’s also possible to automate this.

Let’s walk through the process of automating it by making a working thing.

What are we making?

We’ll make a color palette, which is a common feature in pattern libraries. We’ll generate a grid of color swatches from our CSS custom properties. 

Here’s the complete demo that we’ll build step-by-step.

A preview of our CSS custom property-driven color palette. Showing six cards, one for each color, including the custom property name and hex value in each card.
Here’s what we’re aiming for.

Let’s set the stage. We’ll use an unordered list to display our palette. Each swatch is a <li> element that we’ll render with JavaScript. 

<ul class="colors"></ul>

The CSS for the grid layout isn’t pertinent to the technique in this post, so we won’t look at in detail. It’s available in the CodePen demo.

Now that we have our HTML and CSS in place, we’ll focus on the JavaScript. Here’s an outline of what we’ll do with our code:

  1. Get all stylesheets on a page, both external and internal
  2. Discard any stylesheets hosted on third-party domains
  3. Get all rules for the remaining stylesheets
  4. Discard any rules that aren’t basic style rules
  5. Get the name and value of all CSS properties
  6. Discard non-custom CSS properties
  7. Build HTML to display the color swatches

Let’s get to it.

Step 1: Get all stylesheets on a page

The first thing we need to do is get all external and internal stylesheets on the current page. Stylesheets are available as members of the global document.

document.styleSheets

That returns an array-like object. We want to use array methods, so we’ll convert it to an array. Let’s also put this in a function that we’ll use throughout this post.

const getCSSCustomPropIndex = () => [...document.styleSheets];

When we invoke getCSSCustomPropIndex, we see an array of CSSStyleSheet objects, one for each external and internal stylesheet on the current page.

The output of getCSSCustomPropIndex, an array of CSSStyleSheet objects

Step 2: Discard third-party stylesheets

If our script is running on https://example.com any stylesheet we want to inspect must also be on https://example.com. This is a security feature. From the MDN docs for CSSStyleSheet:

In some browsers, if a stylesheet is loaded from a different domain, accessing cssRules results in SecurityError.

That means that if the current page links to a stylesheet hosted on https://some-cdn.com, we can’t get custom properties — or any styles — from it. The approach we’re taking here only works for stylesheets hosted on the current domain.

CSSStyleSheet objects have an href property. Its value is the full URL to the stylesheet, like https://example.com/styles.css. Internal stylesheets have an href property, but the value will be null.

Let’s write a function that discards third-party stylesheets. We’ll do that by comparing the stylesheet’s href value to the current location.origin.

const isSameDomain = (styleSheet) => {   if (!styleSheet.href) {     return true;   } 
   return styleSheet.href.indexOf(window.location.origin) === 0; };

Now we use isSameDomain as a filter ondocument.styleSheets.

const getCSSCustomPropIndex = () => [...document.styleSheets]   .filter(isSameDomain);

With the third-party stylesheets discarded, we can inspect the contents of those remaining.

Step 3: Get all rules for the remaining stylesheets

Our goal for getCSSCustomPropIndex is to produce an array of arrays. To get there, we’ll use a combination of array methods to loop through, find values we want, and combine them. Let’s take a first step in that direction by producing an array containing every style rule.

const getCSSCustomPropIndex = () => [...document.styleSheets]   .filter(isSameDomain)   .reduce((finalArr, sheet) => finalArr.concat(...sheet.cssRules), []);

We use reduce and concat because we want to produce a flat array where every first-level element is what we’re interested in. In this snippet, we iterate over individual CSSStyleSheet objects. For each one of them, we need its cssRules. From the MDN docs:

The read-only CSSStyleSheet property cssRules returns a live CSSRuleList which provides a real-time, up-to-date list of every CSS rule which comprises the stylesheet. Each item in the list is a CSSRule defining a single rule.

Each CSS rule is the selector, braces, and property declarations. We use the spread operator ...sheet.cssRules to take every rule out of the cssRules object and place it in finalArr. When we log the output of getCSSCustomPropIndex, we get a single-level array of CSSRule objects.

Example output of getCSSCustomPropIndex producing an array of CSSRule objects

This gives us all the CSS rules for all the stylesheets. We want to discard some of those, so let’s move on.

Step 4: Discard any rules that aren’t basic style rules

CSS rules come in different types. CSS specs define each of the types with a constant name and integer. The most common type of rule is the CSSStyleRule. Another type of rule is the CSSMediaRule. We use those to define media queries, like @media (min-width: 400px) {}. Other types include CSSSupportsRule, CSSFontFaceRule, and CSSKeyframesRule. See the Type constants section of the MDN docs for CSSRule for the full list.

We’re only interested in rules where we define custom properties and, for the purposes in this post, we’ll focus on CSSStyleRule. That does leave out the CSSMediaRule rule type where it’s valid to define custom properties. We could use an approach that’s similar to what we’re using to extract custom properties in this demo, but we’ll exclude this specific rule type to limit the scope of the demo.

To narrow our focus to style rules, we’ll write another array filter:

const isStyleRule = (rule) => rule.type === 1;

Every CSSRule has a type property that returns the integer for that type constant. We use isStyleRule to filter sheet.cssRules.

const getCSSCustomPropIndex = () => [...document.styleSheets]   .filter(isSameDomain)   .reduce((finalArr, sheet) => finalArr.concat(     [...sheet.cssRules].filter(isStyleRule)   ), []);

One thing to note is that we are wrapping ...sheet.cssRules in brackets so we can use the array method filter.

Our stylesheet only had CSSStyleRules so the demo results are the same as before. If our stylesheet had media queries or font-face declarations, isStyleRule would discard them.

Step 5: Get the name and value of all properties

Now that we have the rules we want, we can get the properties that make them up. CSSStyleRule objects have a style property that is a CSSStyleDeclaration object. It’s made up of standard CSS properties, like color, font-family, and border-radius, plus custom properties. Let’s add that to our getCSSCustomPropIndex function so that it looks at every rule, building an array of arrays along the way:

const getCSSCustomPropIndex = () => [...document.styleSheets]   .filter(isSameDomain)   .reduce((finalArr, sheet) => finalArr.concat(     [...sheet.cssRules]       .filter(isStyleRule)       .reduce((propValArr, rule) => {         const props = []; /* TODO: more work needed here */         return [...propValArr, ...props];       }, [])   ), []);

If we invoke this now, we get an empty array. We have more work to do, but this lays the foundation. Because we want to end up with an array, we start with an empty array by using the accumulator, which is the second parameter of reduce. In the body of the reduce callback function, we have a placeholder variable, props, where we’ll gather the properties. The return statement combines the array from the previous iteration — the accumulator — with the current props array.

Right now, both are empty arrays. We need to use rule.style to populate props with an array for every property/value in the current rule:

const getCSSCustomPropIndex = () => [...document.styleSheets]   .filter(isSameDomain)   .reduce((finalArr, sheet) => finalArr.concat(     [...sheet.cssRules]       .filter(isStyleRule)       .reduce((propValArr, rule) => {         const props = [...rule.style].map((propName) => [           propName.trim(),           rule.style.getPropertyValue(propName).trim()         ]);         return [...propValArr, ...props];       }, [])   ), []);

rule.style is array-like, so we use the spread operator again to put each member of it into an array that we loop over with map. In the map callback, we return an array with two members. The first member is propName (which includes color, font-family, --color-accent, etc.). The second member is the value of each property. To get that, we use the getPropertyValue method of CSSStyleDeclaration. It takes a single parameter, the string name of the CSS property. 

We use trim on both the name and value to make sure we don’t include any leading or trailing whitespace that sometimes gets left behind.

Now when we invoke getCSSCustomPropIndex, we get an array of arrays. Every child array contains a CSS property name and a value.

Output of getCSSCustomPropIndex showing an array of arrays containing every property name and value

This is what we’re looking for! Well, almost. We’re getting every property in addition to custom properties. We need one more filter to remove those standard properties because all we want are the custom properties.

Step 6: Discard non-custom properties

To determine if a property is custom, we can look at the name. We know custom properties must start with two dashes (--). That’s unique in the CSS world, so we can use that to write a filter function:

([propName]) => propName.indexOf("--") === 0)

Then we use it as a filter on the props array:

const getCSSCustomPropIndex = () =>   [...document.styleSheets].filter(isSameDomain).reduce(     (finalArr, sheet) =>       finalArr.concat(         [...sheet.cssRules].filter(isStyleRule).reduce((propValArr, rule) => {           const props = [...rule.style]             .map((propName) => [               propName.trim(),               rule.style.getPropertyValue(propName).trim()             ])             .filter(([propName]) => propName.indexOf("--") === 0); 
           return [...propValArr, ...props];         }, [])       ),     []   );

In the function signature, we have ([propName]). There, we’re using array destructuring to access the first member of every child array in props. From there, we do an indexOf check on the name of the property. If -- is not at the beginning of the prop name, then we don’t include it in the props array.

When we log the result, we have the exact output we’re looking for: An array of arrays for every custom property and its value with no other properties.

The output of getCSSCustomPropIndex showing an array of arrays containing every custom property and its value

Looking more toward the future, creating the property/value map doesn’t have to require so much code. There’s an alternative in the CSS Typed Object Model Level 1 draft that uses CSSStyleRule.styleMap. The styleMap property is an array-like object of every property/value of a CSS rule. We don’t have it yet, but If we did, we could shorten our above code by removing the map:

// ... const props = [...rule.styleMap.entries()].filter(/*same filter*/); // ...

At the time of this writing, Chrome and Edge have implementations of styleMap but no other major browsers do. Because styleMap is in a draft, there’s no guarantee that we’ll actually get it, and there’s no sense using it for this demo. Still, it’s fun to know it’s a future possibility!

We have the data structure we want. Now let’s use the data to display color swatches.

Step 7: Build HTML to display the color swatches

Getting the data into the exact shape we needed was the hard work. We need one more bit of JavaScript to render our beautiful color swatches. Instead of logging the output of getCSSCustomPropIndex, let’s store it in variable.

const cssCustomPropIndex = getCSSCustomPropIndex();

Here’s the HTML we used to create our color swatch at the start of this post:

<ul class="colors"></ul>

We’ll use innerHTML to populate that list with a list item for each color:

document.querySelector(".colors").innerHTML = cssCustomPropIndex.reduce(   (str, [prop, val]) => `$ {str}<li class="color">     <b class="color__swatch" style="--color: $ {val}"></b>     <div class="color__details">       <input value="$ {prop}" readonly />       <input value="$ {val}" readonly />     </div>    </li>`,   "");

We use reduce to iterate over the custom prop index and build a single HTML-looking string for innerHTML. But reduce isn’t the only way to do this. We could use a map and join or forEach. Any method of building the string will work here. This is just my preferred way to do it.

I want to highlight a couple specific bits of code. In the reduce callback signature, we’re using array destructuring again with [prop, val], this time to access both members of each child array. We then use the prop and val variables in the body of the function.

To show the example of each color, we use a b element with an inline style:

<b class="color__swatch" style="--color: $ {val}"></b>

That means we end up with HTML that looks like:

<b class="color__swatch" style="--color: #00eb9b"></b>

But how does that set a background color? In the full CSS we use the custom property --color as the value of  background-color for each .color__swatch. Because external CSS rules inherit from inline styles, --color  is the value we set on the b element.

.color__swatch {   background-color: var(--color);   /* other properties */ }

We now have an HTML display of color swatches representing our CSS custom properties!


This demo focuses on colors, but the technique isn’t limited to custom color props. There’s no reason we couldn’t expand this approach to generate other sections of a pattern library, like fonts, spacing, grid settings, etc. Anything that might be stored as a custom property can be displayed on a page automatically using this technique.

The post How to Get All Custom Properties on a Page in JavaScript appeared first on CSS-Tricks.

CSS-Tricks

, , ,
[Top]

Adding CSS to a Page via HTTP Headers

Only Firefox supports it, but if you return a request with a header like this:

Header add Link "<style.css>;rel=stylesheet;media=all"

…that will link to that stylesheet without you having to do it in the HTML. Louis Lazaris digs into it:

[…] the only thing I can think of that could justify use for this in production is as a way to include some Firefox-only CSS, which Eric Meyer mentions as a possibility in an old post on this subject. But it’s not guaranteed to always only work in Firefox, so that’s still a problem.

Do with this what you like, but it’s extremely unlikely that this will have any use in a real project.

I appreciate some classic CSS trickery.

Direct Link to ArticlePermalink

The post Adding CSS to a Page via HTTP Headers appeared first on CSS-Tricks.

CSS-Tricks

, , ,
[Top]

Phuoc Nguyen’s One Page Wonders

I keep running across these super useful one page sites, and they keep being by the same person! Like this one with over 100 vanilla JavaScript DOM manipulation recipes, this similar one full of one-liners, and this one with loads of layouts. For that last one, making 91 icons for all those design patterns is impressive alone. High five, Phuoc.

This is my favorite sort of marketing. Some of the products aren’t free, like the React PDF Viewer. How do you get people to know about your paid thing? Give a bunch of useful stuff away for free and have the paid thing sitting right next to it.

The post Phuoc Nguyen’s One Page Wonders appeared first on CSS-Tricks.

CSS-Tricks

, , ,
[Top]

Indicating Scroll Position on a Page With CSS

Scrolling is something we all know and do on the web to the extent that it’s an expectation or perhaps even a habit, like brushing our teeth. That’s probably why we don’t put too much thought into designing the scrolling experience — it’s a well-known basic function. In fact, the popular “there is no fold” saying comes from the idea that people know how to scroll and there is no arbitrary line that people don’t go under.

Scroll-based features tend to involve some bespoke concoction of CSS and JavaScript. That’s because there simply aren’t that many native features available to do it. But what if we could accomplish something that only uses CSS? 

Take this ingenious horizontal scrollbar with CSS, for instance. I want to do something similar, but to indicate scrolled sections rather than capture continuous scrolling. In other words, rather than increasing the length of the indicator during scroll, I only want to increase the length when a certain section of the page has been reached.

Like this:

Here’s my plan: Each section carries an indicator that’s undetectable until it reaches the top of the screen. That’s where it becomes visible by changing color and sticks to the top of the viewport.

The exact opposite should happen in reverse: the indicator will follow along when scrolling back up the screen, camouflaging itself back to being undetected to the naked eye.

There are two key parts to this. The first is for the indicator to change color when it’s near the top of the screen. The second is for the indicator to stay put at the top of the screen and come down only when its section is scrolled down to.

The second one is easy to do: we use position: sticky; on our elements. When a page is scrolled, a sticky element sticks to a given position on the screen within its parent container.

That brings us to changing colors. Since the background of an HTML document is white by default, I’m keeping white as the base color for the demo. This means the indicator should look white when it’s over the base color and turn to some other color when it’s over the indicator bar at the top of the screen.

The dashed indicator is currently invisible, but becomes visible when it sticks to the top and blends with the background color of the indicator container.

This is where CSS blend modes come into play. They give us so many options to create a variety of color amalgams. I’m going to go with the overlay value. This one is quite dynamic in nature. I won’t explain the blend in depth (because the CSS-Tricks Alamanac already does a good job of that) but taking this demo into account, I’ll say this: when the background color is white the resulting foreground color is white; and when the background is some other color, the resulting color is darker or lighter, depending on the color it’s mixed with.

The indicator stops in the demo are black. But, because of the blend, we see them as white because they are on a white background. And when they are over the indicator container element, which is a lovely shade of violet, we see a dark violet indicator stop, because we’re mixing the indicator stop’s black with the indicator container’s violet.

Starting with the HTML:

<div id="passageWrapper">   <strong>Sections Scrolled ↴</strong>   <!-- Indicator container -->   <div id="passage"></div> </div> 
 <!-- Indicator stop --> <div class=passageStops></div> 
 <!-- First Section --> <div class="sections">   <!-- Content --> </div> 
 <!-- Another indicator stop --> <div class="passageStops"></div> 
 <!-- Second Section --> <div class="sections">   <!-- Content --> </div> 
 <!-- Another indicator stop --> <div class="passageStops"></div> 
 <!-- Third Section --> <div class="sections">   <!-- Content --> </div>

Pretty straightforward, right? There’s a sticky container at the very top that holds the indicators when they reach the top.  From there, we have three sections of content, each one topped with an indicator that will stick to the top with the indicator and blend with it.

Here’s the CSS:

.passageStops {   background-color: black; /* Each indicator stop is black */   mix-blend-mode: overlay; /* This makes it appear white on a white background */   width: 33.3%; /* Three sections total, so each section is one-third */   top: calc(1em + 3px); } 
 #passage,  .passageStops{   height: 10px; } 
 #passageWrapper, .passageStops {   position: sticky; /* The container and stops should stick to the top */   z-index: 1; /* Make sure the indicator and stops stay at the forefront */ } 
 #passage {   background: violet; /* Will blend with black to make a darker violet indicator */   margin: 0 0 20px 0; } 
 #passageWrapper{   background-color: white; /* Make sure we're working with white to hide indicator stops */   height: 40px;   top: 0px; } 
 /* Each stop will shift one-third the width of the indicator container to cover the whole thing when the last section is reached. */ .passageStops:nth-child(4){ margin-left: 33.3%; } .passageStops:nth-child(6){ margin-left: 66.6%; } 
 /* More styling, blah blah. */

The indicators (.passageStops) are black. But the overlay blend mode makes them appear white when it blends with the white background under it. Since there are three sections, each indicator is of one-third width.

The indicators have position: sticky; with a top distance value. This means the indicators will stick once they reach the calculated position from the top of the screen. When that happens, the black indicators that appeared white blend with the violet indicator container, which makes them appear to be a dark violet, representing the new scroll position on the page.

The reverse is also true. When an indicator loses its sticky position, it will move from the violet background of the indicator bar to the white background of the page, hiding it once again… like it was never there!

Here’s the demo again:

That’s it. You can perhaps further experiment with this by having a non-white background with another blend mode, or a gradient for the indicator bar or stops.

The post Indicating Scroll Position on a Page With CSS appeared first on CSS-Tricks.

CSS-Tricks

, , ,
[Top]

How to Customize the WooCommerce Cart Page on a WordPress Site

A standard e-commerce site has a few common pages. There are product pages, shop pages that list products, and let’s not forget pages for the user account, checkout flow and cart.

WooCommerce makes it a trivial task to set these up on a WordPress site because it provides templates for them and create the pages for you right out of the box. This is what makes it easy to get your store up and running in a few minutes just by setting up some products and your payment processing details. WooCommerce is very helpful that way.

But this isn’t a post extolling the virtues of WooCommerce. Instead, let’s look at how we can customize parts of it. Specifically, I want to look at the cart. WooCommerce is super extensible in the sense that it provides a ton of filters and actions that can be hooked into, plus a way to override the templates in a WordPress theme. The problem is, those take at least some intermediate-level dev chops which may not be feasible for some folks. And, at least in my experience, the cart page tends to be the most difficult to grok and customize.

Let’s look at how to change the WooCommerce cart page by implementing a different layout. This is how a standard default cart page looks:

We’ll go for something like this instead:

Here’s what’s different:

  • We’re adopting a two-column layout instead of the single full-width layout of the default template. This allows us to bring the “Cart totals” element up top so it is more visible on larger screens.
  • We’re adding some reassurance for customers by including benefits below the list of products in the cart. This reminds the customer the value they’re getting with their purchase, like free shipping, easy exchanges, customer support and security.
  • We’re including a list of frequently asked questions beneath the list of products in an accordion format. This helps the customer get answers to questions about their purchase without have to leave and contact support.

This tutorial assumes that you have access to your theme files. If you don’t feel comfortable logging in to your hosting server and going to the file manager, I would suggest you install the plugin WP File Manager. With just the free version, you can accomplish everything explained here.

First, let’s roll our own template

One of the many benefits of WooCommerce is that it gives us pre-designed and coded templates to work with. The problem is that those template files are located in the plugin folder. And if the plugin updates in the future (which it most certainly will), any changes we make to the template will get lost. Since directly editing plugin files is a big ol’ no-no in WordPress, WooCommerce lets us modify the files by making copies of them that go in the theme folder.

It’s a good idea to use a child theme when making these sorts of changes, especially if you are using a third-party theme. That way, any changes made to the theme folder aren’t lost when theme updates are released.

To do this, we first have to locate the template we want to customize. That means going into the site’s root directory (or wherever you keep your site files if working locally, which is a great idea) and open up the /wp-content where WordPress is installed. There are several folders in there, one of which is /plugins. Open that one up and then hop over to the /woocommerce folder. That’s the main directory for all-things-WooCommerce. We want the cart.php file, which is located at:

/wp-content/plugins/woocommerce/templates/cart/cart.php

Let’s open up that file in a code editor. One of the first things you’ll notice is a series of comments on top of the file:

/**  * Cart Page  *  * This template can be overridden by copying it to yourtheme/woocommerce/cart/cart.php. // highlight  *  * HOWEVER, on occasion WooCommerce will need to update template files and you  * (the theme developer) will need to copy the new files to your theme to  * maintain compatibility. We try to do this as little as possible, but it does  * happen. When this occurs the version of the template file will be bumped and  * the readme will list any important changes.  *  * @see     https://docs.woocommerce.com/document/template-structure/  * @package WooCommerce/Templates  * @version 3.8.0  */

The highlighted line is exactly what we’re looking for — instructions on how to override the file! How kind of the WooCommerce team to note that up front for us.

Let’s make a copy of that file and create the file path they suggest in the theme:

/wp-content/themes/[your-theme]/woocommerce/cart/cart.php

Drop the copied file there and we’re good to start working on it.

Next, let’s add our own markup

The first two things we can tackle are the benefits and frequently asked questions we identified earlier. We want to add those to the template.

Where does our markup go? Well, to make the layout look the way we laid it out at the beginning of this post, we can start below the cart’s closing table </table> , like this:

</table>  <!-- Custom code here -->  <?php do_action( 'woocommerce_after_cart_table' ); ?>

We won’t cover the specific HTML that makes these elements. The important thing is knowing where that markup goes.

Once we’ve done that, we should end up with something like this:

Now we have all the elements we want on the page. All that’s left is to style things up so we have the two-column layout.

Alright, now we can override the CSS

We could’ve add more markup to the template to create two separate columns. But the existing markup is already organized nicely in a way that we can accomplish what we want with CSS… thanks to flexbox!

The first step involves making the .woocommerce  element a flex container. It’s the element that contains all our other elements, so it makes for a good parent. To make sure we’re only modifying it in the cart and not other pages (because other templates do indeed use this class), we should scope the styles to the cart page class, which WooCommerce also readily makes available.

.woocommerce-cart .woocommerce {   display: flex; }

These styles can go directly in your theme’s style.css file. That’s what WooCommerce suggests. Remember, though, that there are plenty of ways to customize styles in WordPress, some safer and more maintainable than others.

We have two child elements in the .woocommerce element, perfect for our two-column layout: .woocommerce-cart-form and .cart-collaterals. This is the CSS we need to split things up winds up looking something like this:

 /* The table containing the list of products and our custom elements */ .woocommerce-cart .woocommerce-cart-form {   flex: 1 0 70%; /* 100% at small screens; 70% on larger screens */   margin-right: 30px; }  /* The element that contains the cart totals */ .woocommerce-cart .cart-collaterals {   flex: 1 0 30%; /* 100% at small screens; 30% on larger screens */   margin-left: 30px; }  /* Some minor tweak to make sure the cart totals fill the space */ .woocommerce-cart .cart-collaterals .cart_totals {   width: 100%;   padding: 0 20px 70px; }

That gives us a pretty clean layout:

It looks more like Amazon’s cart page and other popular e-commerce stores, which is not at all a bad thing.

Best practice: Make the most important elements stand out

One of the problems I have with WooCommerce’s default designs is that all the buttons are designed the same way. They’re all the same size and same background color.

Look at all that blue!

There is no visual hierarchy on the action users should take and, as such, it’s tough to distinguish, say, how to update the cart from proceeding to checkout. The next thing we ought to do is make that distinction clearer by changing the background colors of the buttons. For that, we write the following CSS:

/* The "Apply Coupon" button */ .button[name="apply_coupon"] {   background-color: transparent;   color: #13aff0; } /* Fill the "Apply Coupon" button background color and underline it on hover */ .button[name="apply_coupon"]:hover {   background-color: transparent;   text-decoration: underline; } 
 /* The "Update Cart" button */ .button[name="update_cart"] {   background-color: #e2e2e2;   color: #13aff0; } /* Brighten up the button on hover */ .button[name="update_cart"]:hover {   filter: brightness(115%); }

This way, we create the following hierarchy: 

  1. The “Proceed to checkout” is pretty much left as-is, with the default blue background color to make it stand out as it is the most important action in the cart.
  2. The “Update cart” button gets a grey background that blends in with the white background of the page. This de-prioritizes it.
  3. The “Apply coupon” is less a button and more of a text link, making it the least important action of the bunch.

The full CSS that you have to add to make this design is here:

@media(min-width: 1100px) {   .woocommerce-cart .woocommerce {     display: flex;   }   .woocommerce-cart .woocommerce-cart-form {     flex: 1 0 70%;     margin-right: 30px;   }       .woocommerce-cart .cart-collaterals {     flex: 1 0 30%;     margin-left: 30px;   } } 
 .button[name="apply_coupon"] {   background-color: transparent;   color: #13aff0; } 
 .button[name="apply_coupon"]:hover {   text-decoration: underline;   background-color: transparent;   color: #13aff0; } 
 .button[name="update_cart"] {   background-color: #e2e2e2;   color: #13aff0; } 
 .button[name="update_cart"]:hover {   background-color: #e2e2e2;   color: #13aff0;   filter: brightness(115%); }

That’s a wrap!

Not too bad, right? It’s nice that WooCommerce makes itself so extensible, but without some general guidance, it might be tough to know just how much leeway you have to customize things. In this case, we saw how we can override the plugin’s cart template in a theme directory to future-proof it from future updates, and how we can override styles in our own stylesheet. We could have also looked at using WooCommerce hooks, the WooCommerce API, or even using WooCommerce conditions to streamline customizations, but perhaps those are good for another post at another time.

In the meantime, have fun customizing the e-commerce experience on your WordPress site and feel free to spend a little time in the WooCommerce docs — there are lots of goodies in there, including pre-made snippets for all sorts of things.

The post How to Customize the WooCommerce Cart Page on a WordPress Site appeared first on CSS-Tricks.

CSS-Tricks

, , , , ,
[Top]

This Page is Designed to Last

Jeff Huang, while going through his collection of bookmarks, sadly finds a lot of old pages gone from the internet. Bit rot. It’s pretty bad. Most of what gets published on the web disappears. Thankfully, the Internet Archive gets a lot of it. Jeff has seven things that he thinks will help make a page last.

1) Return to vanilla HTML/CSS
2) Don’t minimize that HTML
3) Prefer one page over several
4) End all forms of hotlinking
5) Stick with the 13 web safe fonts +2
6) Obsessively compress your images
7) Eliminate the broken URL risk

I don’t take issue with any of that advice in general, but to me, they don’t all feel like things that have much to do with whether a site will last or not. Of them, #4 seems like the biggest deal, and #5 is… strange. (Fonts fall back on the web; what fonts you use should have no bearing on a site’s ability to last.)

I sort of agree with #1 and #2, but not on the surface. Both of them imply a build process. Build processes get old, they stop working, and they become a brick of technical debt. I still love them and can’t imagine day-to-day work without them, but they are things that stands in the way of people wanting to deal with an old site. Highly relevant, Simplicity, notes from Bastian Allgeier’s article.

Everything listed is technological. If we’re talking technological advice to keeping a site online for the long haul, I’d say jamstack is the obvious answer. Prerender everything into static files. Rely on no third-party stuff anything, except a host. (Disclosure: Netlify is a current sponsor of this site, but I’m tellin’ ya, toss a simple static site without a complex build process up on Netlify, which has a generous free tier, and that site will absolutely be there for the long haul. )

Don’t diddle with your URLs either. Gosh darn it if I don’t see a lot of 404s because someone up and changed up all their URLs.

But I feel there is something beyond the technological that is the real trick to a site that lasts: you need to have some stake in the game. You don’t let your URLs die because you don’t want them to. They matter to you. You’ll tend to them if you have to. They benefit you in some way, so you’re incentivized to keep them around. That’s what makes a page last.

Direct Link to ArticlePermalink

The post This Page is Designed to Last appeared first on CSS-Tricks.

CSS-Tricks

, , ,
[Top]