⭐ If you would like to buy me a coffee, well thank you very much that is mega kind! : https://www.buymeacoffee.com/honeyvig Hire a web Developer and Designer to upgrade and boost your online presence with cutting edge Technologies

Tuesday, August 1, 2023

Exploring Universal And Cognitive-Friendly UX Design Through Pivot Tables And Grids

 The main task of data visualization is to present information in a form that is easier for human perception. But often, the main enemy of good visualization is hidden in the efforts to do it beautifully. From this point of view, tables are the most difficult to understand and design as they contain a lot of elements. This article has collected the best tips and recommendations on the elements to pay attention to, the rules to follow, and life hacks to get around certain difficulties. In addition, all this is supported by a pinch of neuropsychology and some scientific terms to give a deeper understanding of the problem and, therefore, possible solutions.

Tables are one of the most popular ways to visualize data. Presenting data in tables is so ubiquitous — and core to the web itself — that I doubt many of you reading this have any trouble with the basics of the <table> element in HTML. But building a good complex table isn’t an easy task.

Though, I’d even go so far as to say that tables are an integral part of our daily life.

That’s why we need to start thinking about making tables more inclusive. The web is supposed to be designed for everybody. That includes those with impairments that may prevent access to the information in the tables we make and rely on assistive technology to “read” them.

For the last several months, I’ve been working on this scientific project around inclusive design for people with cognitive disorders for my university degree. I’ve mostly focused on developing guidelines to help educational platforms adapt to such users.

I also work for a company that has developed a JavaScript library for creating pivot tables used for business analysis and data visualizations. At one point in my research, I found that tables are a type of popular data representation that can simultaneously be a lifesaver and a troublemaker, yes, for people with learning and cognitive problems, but for everyone else as well. Remember, we are all temporarily “abled” and prone to lose abilities like eyesight and hearing over time.

Plus, a well-executed inclusive table design is a pathway to improving everyone’s productivity and overall experience, regardless of impairment.

 

What We Mean By Cognitive Disorders

Cognitive disorders are defined as any kind of disorder that significantly impairs an individual’s conscious intellectual activity, such as thinking, reasoning, or remembering.

ADHD is one example that prevents a person from remaining focused or paying attention. There’s also dyslexia , which makes it tough to recognize and comprehend written words. Dyscalculia is specific to working with numbers and arithmetic.

For those without this condition, it is difficult to understand what exactly can be wrong with the perception of written information. But based on the descriptions of people with the relevant deviations, simulators were created that imitate what people with dyslexia see.

Currently, you can even install a special browser extension to estimate how difficult your site will be to perceive by people with this deviation. It is much more difficult to understand the condition of people with ADHD, but certain videos with ADHD simulations do exist, which can also allow you to evaluate the level of difficulty in the perception of any information by such people.

These are all things that can make it difficult for people to use tables on the web. Tables are capable of containing lots of information that requires a high level of cognitive work.

  • The first stage toward helping users with such deviations is to understand their condition and feel its details on themselves — in other words, practicing empathy.
  • The second stage is to systematize the details and identify specific usability problems to solve.

Please indulge me as we dive a bit into some psychological theory that is important to understand when designing web pages.

Cognitive Load

Cognitive load relates to the amount of information that working memory can hold at one time. Our memory has a limited capacity, and instructional methods should avoid overloading it with unnecessary activities and information that competes with what the individual needs to complete their task.

UX professionals often say complex tasks that require the use of external resources may result in an increased cognitive load. But the amount of the load can be affected by any additional information, unusual design, or wrong type of data visualization. When a person is accustomed to a particular representation of certain types of data — like preferred date format or where form input labels are positioned — even a seemingly minor change increases the processing time of our brain.

Here’s an example: If a particular student is from a region where content is presented in a right-to-left direction and the software they are provided by their university only supports a left-to-right direction, the amount of mental work it takes to comprehend the information will be greater compared to other students.

If you still want another example, Anne Gibson explains this exceptionally well in a blog post that uses ducks to illustrate the idea.

Cognitive Biases #

I also want to call special attention to cognitive biases, which are systematic errors in thinking that become patterns of deviation from rationality in judgment. When people are processing and interpreting information around them, it often can influence the decisions a person makes without even noticing.

For example, the peak-end rule says that people judge an experience by its “peak” and last interactions. It’s easy to prove. Try to reflect on a game you used to play as a kid, whether it’s from an arcade, a computer console, or something you played online. What do you remember about it? Probably the level that was hardest for you and the ending. That’s the“peak” of your experience and the last, most “fresh” one, and they create your overall opinion of the game. For more examples, there is a fantastic resource that outlines 106 different types of cognitive biases and how they affect UX.

Signal-to-noise Ratio

Last but not least, I’d like to touch on the concept of a signal-to-noise ratio briefly. It is similar to the engineering term but relates to the concept that most of the information we encounter is noise that has nothing to do with a user’s task.

  • Relevant and necessary information is a signal.
  • The ratio is the proportion of relevant information to irrelevant information.

A designer’s goal is to achieve a high signal-to-noise ratio because it increases the efficiency of how information is transmitted. The information applied to this ratio can be anything: text, illustrations, cards, tables, and more.

The main idea about cognitive disabilities I want you to take away is that they make individuals very sensitive to the way the information is presented. A font that’s too small or too bright will make content unperceivable. Adding gratuitous sound or animation may result in awful distractions (or worse) instead of nice enhancements.

I’ll repeat it:

A good user experience will prevent cognitive overload for everyone. It’s just that we have to remember that many out there are more sensitive to such noises and loads.

Focusing on individuals with specific considerations only gives you a more detailed view of what you need to solve for everybody to live a simpler life.

Considering Cognitive Disorders In UX Design

Now that we have defined the main problems that can arise in a design, I can sum up our goals for effective UX:

  • Reduce the cognitive load.
  • Maximize the signal-to-noise ratio.
  • Use correct cognitive biases to boost the user experience.

“Design” is a loaded term meaning lots of different things, from colors and fonts to animations and sounds and everything in between. All of that impacts the way an individual understands the information that is presented to them. This does not mean all design elements should be excluded when designing table elements. A good table design is invisible. The design should serve content, not the other way around.

With the help of lots of academic, professional, and personal research, I’ve developed a set of recommendations that I believe will result in cognitive-friendly and easy-to-perceive table designs.

Color Palettes And Usage

We should start by talking about the color because if the colors used in a table are improperly implemented, subsequent decisions do not really matter.

Many people consider colors to have their meanings, which differ from culture to culture. That’s certainly true in a sociological sense, but as far as UX is concerned, the outcome is the same — colors carry information and emotions and are often unnecessary to mean something in a design.

Rule 1: Aim For A Minimalist Color Palette #

When you see a generous use of color in a table, it isn’t to make the table more functional but to make a design stand out. I won’t say that using fewer colors guarantees a more functional table, but more color tends to result in individuals losing attention from the right things.

Accordingly, bright colors and accents should highlight information that has established meaning. This isn’t to say that interesting color schemes and advanced color palettes are off-limits. This means using colors wisely. They are a means to an end rather than a splash of paint for attention.

Adam Wathan & Steve Schoger offer a perfect example of color usage in a design study of customized Slack themes. Consider the two following interfaces. It may not seem like it at first, but the second UI actually has a more extensive color palette than the first.

The difference is that the second interface applies shades of the core color defined in the palette and that brighter and more vibrant shades are only used to highlight the important stuff.

You can explore this phenomenon by yourself and test your perception of the colors in the design by changing the look of your messenger. For example, Telegram has some interface customization options, and while playing with that, I noticed I read and navigate between my chats in the “Night Accent” mode rather than the plain “System” mode.

Of course, both designs were designed for people with different preferences and characteristics, but such a personal experiment led me to the following thought. Even though the second option uses fewer colors, the uniformity of information is a bit confusing. From this, I concluded that too few colors and too minimal a design is also a bad choice. It is necessary to find a balance between the color palette and its usage.

The best option is to pick from one to three primary colors and then play with their shades, tints, and tones. To combine the colors wisely, you can use complementary, split complementary, or analogous approaches.

That said, I suggest using a “shading” monochromatic approach for tables. It means defining a base color in a palette, then expanding it with different shades in dark and light directions. In other words:

  1. Choose a primary color.
  2. Define an evenly darker and lighter shade of that primary color.

This produces two more colors to which you can apply the previous technic to create colors that are a perfect compromise between the shades on either side. Repeat this process until you reach the number of colors you need (generally, 7–9 shades will do).

Rule 2: Embrace The Power Of Whitespace

I find that it’s good to offer a fair amount of “breathing room” around elements rather than trying to crowd everything in as close as possible. For example, finding a balance of space between the table rows and columns enhances the legibility of the contents as it helps distinguish the UI from the information.

I’ll qualify this by noting that “breathing room” often depends on the type of data that’s being presented, as well as the size of the device on which it’s being viewed. As such, it sometimes makes sense to enhance a table’s functionality by allowing the user to adjust the height and width of rows and columns for the most optimal experience.

If you are worried about using too few or too many colors, apply the 60/30/10 rule. It’s a basic pattern for any distribution selection. People use this strategy when budgeting assets like content and media, and it’s applicable to design. The rule says the color usage should be distributed as follows:

  • 60% for neutral colors,
  • 30% for primary colors,
  • 10% for secondary colors (e.g., highlights, CTAs, and alerts).

Rule 3: Avoid Grays

Talking about neutral colors, in color theory, gray represents neutrality and balance. Its color meaning likely comes from being the shade between white and black and often is also perceived as the absence of color. You can not overdo it; its light shades do not oppress, so gray is just “okay.”

However, gray does carry some negative connotations, particularly when it comes to depression and loss. Its absence of color makes it dull. For this reason, designers often resort to it to de-emphasize an element or certain bits of data.

But maintaining such a philosophy of gray color will only work in black and white designs, such as on the Apple website. Though, as I mentioned before, it actually works really well as grey is the tone of black or a shade of white.

The problem, however, comes up when other colors are added to the color palette, which leads to a change in a color’s roles and functions. In the case of gray, putting it next to brighter colors makes the design pale and dull.

Having no color of its own, gray seems to eat away the brightness of neighboring elements. Instead of maintaining balance, gray makes the design cloudy and unclear. After all, against the background of already illuminated elements, gray makes the elements not just less significant but unnecessary for our perception.

That does not mean you should totally give up gray. But highlighting some information inherently de-emphasizes other information, negating the need for gray in the first place.

The easy way out is to replace gray with lighter shades of a palette’s base color on a table cell’s background. The effect is the same, but the overall appearance will pop more without adding more noise or cognitive load.

Rule 4: Know What’s Worthy Of Highlighting

Designers are always looking for a way to make their work stand out. I get the temptation because bold and bright colors are definitely exciting and interesting.

Blogs can be considered a good example of this problem as their variety is wide and growing, and a lot of platforms prioritize exclusive design over inclusive design.

For example, Medium uses only black and shades of it for a color palette, which significantly facilitates even simple tasks like reading titles. Hackernoon, although looking interesting and drawing attention, requires more concentration and does not allow you to “breathe” as freely as on Medium.

In analytical software, that only leads to a table design that emphasizes a designer’s needs ahead of the user’s needs.

Don’t get me wrong — a palette that focuses on shades rather than a large array of exciting colors can still be exciting and interesting. That provides a discussion about which grid elements benefit from color. Here are my criteria for helping decide what those are and the colors that add the most benefit for the given situation.

Active cells: If the user clicks on a specific table cell or selects a group of cells, we can add focus to it to indicate the user’s place in the data. The color needs to call attention to the selection without becoming a distraction, perhaps by changing the border color with a base color and using a light shade of it for the background so as to maintain WCAG-compliant contrast with the text color.

Tip! It’s also good to highlight the row and column that a focused cell belongs to, as this information is a common thing to check when deciphering the cell’s meaning. You can highlight the entire row and column it belongs to or, even better, just the first cell of the row and column.

Error messaging: Error messages definitely benefit from color because, in general, errors contain critical feedback for the user to take corrective action.

A good example might be an injected alert that informs the user that the table’s functionality is disabled until an invalid data point is fixed. Reds, oranges, and yellows are commonly used in these situations but bear in mind that overly emphasizing an error can lead to panic and stress. (Speaking of error messaging, Vitaly Friedman has an extensive piece on designing effective error messages, including the pitfalls of relying too heavily on color.)

Outstanding data: I’m referring to any data in the table that is an outlier. For example, in a table that compares data points over time, we might want to highlight the high and low points for the sake of comparison. I suggest avoiding reds and greens, as they are commonly used to indicate success and failure. Perhaps styling the text color with a darker shade of a palette’s base color is all you need to call enough attention to these points without the user losing track of them.

The key takeaway:

Data-heavy tables are already overwhelming, and we don’t want any additional noise. Try to remove all unnecessary colors that add to a user’s cognitive load.

Tip! Remember the main goal when designing a table: reliability, not beauty. Always check your final decisions, ideally with a variety of target users. I really recommend using contrast checkers to spot mistakes quickly and efficiently correct them.

Typographical Considerations

The fonts we use to represent tabular data are another aspect of a table’s look and feel that we need to address when it comes to implementing an inclusive design. We want the data to be as legible and scannable as possible, and I’ve found that the best advice boils down to the typography of the content — especially for numerics — as well as how it is aligned.

Rule 1: The Best Font Is A “Simple” Font

The trick with fonts is the same as with colors: simplicity. The most effective font is one that takes less brainpower to interpret rather than one that tries to stand out.

No, you don’t need to ditch your Google Fonts or any other font library you already use, but choose a font from it that meets these recommendations:

  1. Sans-serif fonts (e.g., Helvetica, Arial, and Verdana) are more effective because they tend to take up less space in a dense area — perfect for promoting more “breathing room” in a crowded table of data.
  2. A large x-height is always easier to read. The X-height is the height of the body of a lowercase letter minus any ascenders or descenders. In other words, the height of the lowercase “x” in the font.
  3. Monospace fonts make it easier to compare cells because the width of each character is consistent, resulting in evenly-spaced lines and cells.
  4. Regular font weights are preferable to bolder weights because the boldfacing text is another form of highlighting or emphasizing content, which can lead to confusion.
  5. A stable, open counter. The counter is a space in the letter “o” or the letter “b.” Fonts with distorted counters render poorly in small sizes and are hard to read.

Fonts that fulfill these criteria are more legible and versatile than others and should help whittle down the number of fonts you have to choose from when choosing your table design.

Rule 2: Number Formatting Matters

When choosing a font, designers often focus on good legible letters and forget about numbers. Needless to say, numbers often are what we’re displaying in tables. They deserve first-class consideration when it comes to choosing an effective font for a good table experience.

As I mentioned earlier, monospace fonts are an effective option when numbers are a table’s primary content. The characters take up the same width per character for consistent spacing to help align values between rows and columns. In my experience, finding a proportional font that doesn’t produce a narrow “1” is difficult.

If you compare the two fonts in the figure above, it’s pretty clear that data is easier to read and compare when the content is aligned and the characters use the same amount of space. There’s less distance for the eye to travel between data points and less of a difference in appearance to consider whether one value is greater than the other.

If you are dealing with fractions, you will want to consider a font that supports that format or go with a variable font that supports font-variant-numeric features for more control over the spacing.

Rule 3: There Are Only Two Table Alignments: Left And Right

Technically there are four alignments: left, right, center, and justify. We know that because the CSS text-alignment property supports all four of them.

My personal advice is to avoid using center alignment, except in less-common situations where unambiguous data is presented with consistently-sized icons. But that’s a significant and rare exception to the rule, and it is best to use caution and good judgment if you have to go there.

Justified content alters the spacing between characters to achieve a consistent line length, but that’s another one to avoid, as the goal is less about line lengths than it is about maintaining a consistent amount of space between characters for a quick scan. That is what monospaced fonts are effective for.

Data should instead be aligned toward the left or right, and which one is based on the user’s language preference.

Then again, at school, we’re taught to compare numbers in a right-to-left direction by looking first at single units, then tens, followed by hundreds, then thousands, and so forth. Accordingly, the right alignment could be a better choice that’s universally easier to read regardless of a person’s language preference. You may notice that spreadsheet apps like Excel, Sheets, and Notion align numeric values to the right by default.

There are exceptions to that rule, of course, because not all numbers are measurements. There are qualitative numbers that probably make more sense with left alignment since that is often the context in which they are used. They aren’t used for comparison and are perceived as a piece of text information written in numbers. Examples include:

  • Dates (e.g., 12/28/2050),
  • Zip/Postal code (e.g., 90815),
  • Phone number (e.g., 555-544-4349).

Table headings should be aligned to the same edge as the data presented in the column. I know there could be disagreement here, as the default UA styling for modern browsers centers table headings.

Though in big data grids, less difference in the header and data design is better as it automatically adjusts to a certain perception.

Rule 4: Pictures Help Convey Meaning

As I mentioned, numbers and text are not the only way to present data. Icons and colors can enhance it with added meaning.

For example, you can use conditional formatting and heat mapping to recreate data patterns in a way that helps the user’s brain process the information in a more efficient manner. This Flexmonster demo is a good example of the effective use of color shading and styled points to make the data easier to interpret at a quick glance.Icons can be a good way to show a decline or increase in indicators or a change in status. Depending on your dataset, you can define measures that can be shown in a more visual way. It will allow users to pay attention to the values that are still to be decoded — text and numbers.

Rule 5: Data > Headers

I’ve seen lots of examples that use bold, bright colors or exaggerated font styling to differentiate table headings from the data. It’s perfectly fine — and even encouraged — to distinguish the two, but not to the extent that the headings overshadow the data.

My advice, though, is to de-emphasize table headers to allow the data to pop. And if there is any secondary information, try to consolidate it and de-emphasize it as well.

The screenshots above are examples of bad and good headers. When looking at the first screenshot, your initial focus is likely drawn to the column headers, which is good! That allows you to understand what the table is about quickly. But after that initial focus, the bold text is distracting and tricks your brain into thinking the header is the most important content.

The header in the second screenshot also uses bold text. However, notice how changing the color from black to white emphasizes the headers at the same time. That negates the impact bolding has, preventing potential cognitive load.

At this point, I should include a reminder to avoid gray when de-emphasizing table elements. For example, notice the numbers in the far left column and very top row. They get lost against the background color of the cells and even further obscured by the intense background color of surrounding cells. There’s no need to de-emphasize what is already de-emphasized.

I also suggest using short labels to prevent them from competing with the data. For example, instead of a heading that reads “Grand Total of Annual Revenue,” try something like “Total Revenue” or “Grand Total” instead.

Table Layout Considerations

There once was a time when tables were used to create webpage layouts because, again, it was a simple and understandable way to present the information in the absence of standardized CSS layout features. That’s not the case today, thankfully, but that period taught us a lot about best practices when working with table design that we can use today.

Rule 1: Fewer Borders = More White Space

Borders are commonly used to distinguish one element from one another. In tables, specifically, they might be used to form outlines around rows and columns. That distinction is great but faces the same challenge that we’ve covered with using color: too much of a layout can steal focus from the data, making the design busy and cluttered. With the proper design and text alignment, however, borders can become unnecessary.

Borders help us navigate the table and delimit individual records. At the same time, if there are many of them in a grid, it becomes a problem in large tables with a lot of rows and columns. To prevent the cells from being too densely connected, try adding more space between them with padding. As I have mentioned before, negative space is not an enemy but a design saver.

That said, the law of diminishing returns applies to how much space there should be, particularly when considering a table’s width. For example, a table might not need to flex to the full width of its parent container by default. It depends on the content, of course. Avoiding large spacing between columns will help prevent a reader’s eyes from having to travel far distances when scanning data and making mistakes.

I know that many front-enders struggle with column widths. Should they be even? Should they only be as wide as the content that’s in them? It’s a juggling act that, in my mind, is not worth the effort. Some cells will always be either too wide or too narrow when table cells contain data points that result in varying line lengths. Embrace that unevenness, allowing columns to take up a reasonable amount of space they need to present the data and scale down to as little as they need without being so narrow that words and numbers start breaking lines.

Lines should be kept to a minimum. Add them if adjusting the alignment, joining cells, and increased spacing is not enough to indicate the direction — or keep them as light as possible.

Allow multi-line wrapping when you really need it, such as when working with longer data points with just enough room around them to indicate the alignment direction. But if you caught yourself thinking of using multi-line wrapping in a grid, then first of all, analyze whether there is a more practical way to visualize the data.

Rule 2: Stylish rows, stylish columns

When deciding how to style a table’s rows, it’s important to understand the purpose of the table you are developing. Reducing visual noise will help to present a clear picture of the data on smaller datasets but not for large datasets.

It’s easy for a user to lose their place when scrolling through a table that contains hundreds or thousands of rows. This is where borders can help a great deal, as well as zebra striping, for a visual cue that helps anchor a user’s eyes enough to hold focus on a spot while scanning.

Speaking of zebra striping, it’s often used as a stylistic treatment rather than a functional enhancement. Being mindful of which colors are used for the striping and how they interact with other colors and shades used for highlighting information will go a long way toward maintaining a good user experience that avoids overwhelming color combinations. I often use a slightly darker shade of the table’s default background color on alternating rows (or columns) when establishing stripes. If that’s white, then I will go with the lightest shade of my palette’s base color. The same choice should be made while maintaining the borders — they should be marked but remain invisible.

Typically, row density gravitates around 40px-56px with a minimum padding of 16px on both the right and left edges of each column.

 

Friday, July 28, 2023

Shines, Perspective, And Rotations: Fancy CSS 3D Effects For Images

 CSS has all kinds of tricks that are capable of turning images into neat, interactive elements. This article is a collection of fancy 3D effects for images that demonstrate those CSS powers. Get ready to learn how they work as we get our hands dirty with CSS features that add perspective, depth, rotation, and even a slick shine to images that you can use on your next project.

We all agree that 3D effects are cool, right? I think so, especially when they are combined with subtle animations. In this article, we will explore a few CSS tricks to create stunning 3D effects!

“Why do we need another article about CSS 3D effects… aren’t there already a million of those?” Yes, but this one is a bit special because we are going to work with the smallest amount of HTML possible. In fact, this is the only markup we will use to craft some pretty amazing CSS effects for images:

<img src="" alt="">

That’s it! All we need is an <img> tag. Everything else will be done in CSS.

Here’s how it’s going to work. We are going to explore three different effects that are not linked to each other but might borrow a little from one another. You don’t need to read the entire article in one sitting. Actually, I suggest reading one section at a time, taking time to understand the concepts and what the underlying code is doing before moving on to another effect.

Table Of Contents #

More after jump! Continue reading below ↓

CSS 3D Shine #

For the first effect, we are going to add a shine animation to the image, as well as a slight rotation when hovered.

See the Pen 3D Shine effect on hover by Temani Afif.

See that? The image starts slightly askew but then straightens out on hover while a shine reflects off the surface. This is a neat way to add a bit of realism to a UI without going overboard.

The first thing I did in that demo was add a rotation to the image in CSS:

img {
  transform: perspective(400px) rotate3d(1, -1, 0, 8deg);
}
img:hover {
  transform: perspective(400px) rotate3d(1, -1, 0, -8deg);
}

rotate3d allows us to define an axis for the image to rotate around. I won’t dig into the math details, but to get a diagonal axis, we make the z-axis equal to 0 and use 1 or -1 for both the x-axis and y-axis.

Then, we use the perspective property to add a little imbalance to the image. There is no particular logic behind the 400px value or the 8deg applied to the rotation, but I’ve found that a small angle combined with a big perspective gives a good result. Feel free to edit them, and maybe you will find better values for your specific use case.

We can simplify this! To avoid repetition on :hover, we can use a CSS variable to update the sign of the angle on hover. That way, there’s no need to re-write the entire declaration simply to change 8deg to -8deg.

img {
  transform: perspective(400px) rotate3d(1, -1, 0, calc(var(--i, 1) * 8deg));
}
img:hover {
  --i: -1;
}

Notice how I’m using calc() in there. By multiplying the degree value by 1 (defined by the --i variable), we get 8deg by default. Then we swap that out by changing 1 to -1 in the hover ruleset and let calc() do the heavy lifting.

That’s fun! But it gets even more interesting when we start working on the shine. An intuitive approach to making a shine might be to rely on an overlay that we place above the image. But remember, we’re working with nothing but a single <img> element, and an overlay would require more markup.

You might also be tempted to reach for a pseudo-element instead. But that’s not going to work here, unfortunately, because they won’t work with the <img> tag.

What we are going to do is “fake” it with a CSS mask and an animated gradient. I am saying “fake” because, in reality, the image you see is partially transparent. On hover, the transparency is updated to create a shiny effect.

I know it’s not easy to grasp, but if you consider that our background is black — and, yes, that is part of the trick! — making the image partially transparent is similar to making the image darker. And when the image is hovered, we adjust the transparency to brighten it up.

Here is a simplified example using opacity to better understand what I mean:

See the Pen Opacity transition by Temani Afif.

That’s the basic idea. Now, instead of opacity, we are going to use mask with a linear-gradient()

/* Diagonal gradient that is opaque 
 * in the center and semi-transparent 
 * on both sides.
*/
mask: linear-gradient(135deg, #000c 40%, #000, #000c 60%);

When masking in CSS, the color doesn’t matter considering the default mask-mode. All that matter is the alpha channel that will define the level of transparency. In our case, the diagonal part is opaque, while the sides are partially transparent. #000c is equivalent to rgb(0 0 0 / 80%).

See the Pen Adding the gradient mask by Temani Afif.

The gradient is super subtle because we only reduced the transparency a little. That’s a good thing because we don’t want the user to notice that the image is partially transparent by default.

The next step is to animate that gradient. We increase its size to the point where the opaque center is out of view. Then we move it from the top-left corner of the image to the bottom-right corner:

img {
  mask:
    linear-gradient(135deg, #000c 40%, #000, #000c 60%)
    100% 100%/ /* initial position, bottom-right */
    240% 240%; /* width and height */
}
img:hover {
    mask-position: 0 0; /* Move to the top-left on hover */
}

Check it out; we have a nice shine on hover!

See the Pen Adding the hover effect by Temani Afif.

Cool, right? Now let’s combine that shine above with the 3D rotation to get the full effect.

img {
  transform: perspective(400px) rotate3d(1,-1,0,calc(var(--i,1)*8deg));
  mask:
    linear-gradient(135deg,#000c 40%,#000,#000c 60%)
    100% 100%/240% 240%;
  transition: .4s;
  cursor: pointer;
}
img:hover {
  --i: -1;
  mask-position: 0 0;
}

One HTML element and a few lines of CSS are all we needed to make that happen. Here is a figure to illustrate the different values used inside the mask:

Demonstrating how the CSS mask covers the image and how it slides on hover
Demonstrating how the CSS mask covers the image and how it slides on hover. (Large preview)

The green box illustrates the gradient where the blue lines define the color stops we used. Initially, it’s placed at 100% 100%, and on hover, we slide it to 0 0. The slide effect will move the diagonal part of the gradient (the opaque part) along the image to create the shine effect.

Here is the full demo again. I’m even including a second variation for you to tear apart and investigate how it works.

See the Pen 3D Shine effect on hover by Temani Afif.

CSS 3D Parallax #

We normally think of “parallax” as this thing we use for interesting scrolling effects where elements change position at different speeds. But we can use it to make a slick hover effect on our image too.

See the Pen 3D parallax effect on hover by Temani Afif.

Like the shine effect we made in the last section, we start with a slightly skewed image that straightens out on hover. But, instead of applying a shine, we’re sliding the image over a smidge with a transition to make it look like the focal point rotates with the image, adding a sense of depth to it.

You might think we need to stack two versions of the same image to pull this off, but not at all! The effect is done with a single image and a few lines of CSS for the “fake” parallax effect. Yes, I’m calling this a “fake” effect because it’s not really a parallax implementation but a combination of movements that trick your brain into thinking it is! If you want to see “real” parallax at work, this pen from Sladjan is a great example.

The image is very important here. For a perfect illusion, consider an image where the main element is placed at the center, and the background is uniform. That might be a bit of a limitation as far as this effect goes, so it might not be the best approach for every image.

The image rotates and changes perspective on hover, just like the shine effect in the last section. This time, however, we’re rotating along the y-axis (rotateY()) instead of all three axes (rotate3d()).

img {
  transform: perspective(400px) rotateY(8deg);
}
img:hover {
  transform: perspective(400px) rotateY(-8deg);
}

We accomplish the sliding movement with a combination of CSS clipping and translation. This is the trickiest part of the effect. Here is a simplified demo to illustrate the main idea:

See the Pen Moving the image inside a box by Temani Afif.

We have an image inside a box with a green border representing the clipped area. The clipped area is square, and the image overflows the right edge a bit. On hover, we slide the image to the left (using transform: translateX()) while the clipped area remains in place.

If we hide the part of the image that overflows the clipped area (overflow: hidden) and add the same rotation we made in the last section, we get the “fake” parallax effect we want:

See the Pen Adding the rotation + the overflow by Temani Afif.

But that demo uses an extra <div> element to pull it off. Our challenge is to do the same thing without that element. That’s where clip-path is really helpful:

img {
  --f: .1; /* parallax factor (the smaller, the better) */

  --_f: calc(100 * var(--f) / (1 + var(--f)));
  width: 250px; /* image size */
  aspect-ratio: calc(1 + var(--f));
  object-fit: cover;
  clip-path: inset(0 var(--_f) 0 0);
  transition: .5s;
}
img:hover {
  clip-path: inset(0 0 0 var(--_f));
  transform: translateX(calc(-1 * var(--_f)))
}

The --f variable controls the effect, describing how much the image should move. You will notice that I am using it to calculate an aspect-ratio that is slightly greater than 1 to create a non-square image that we later clip to get a square image. --_f defines the portion we must cut from the image to get a 1:1 square ratio.

Demonstrating how the clip-path values change when the image is in a hovered state
Demonstrating how the clip-path values change when the image is in a hovered state. (Large preview)

The clip-path defines the clipped area, and we need that area to remain fixed. That’s why we added a translation on hover to move the image in the opposite direction of the clip-path.

See the Pen Clip-path + translation by Temani Afif.

We add the rotation to the mix, and the effect is perfect:

img {
  --f: .1; /* parallax factor (the smaller the better) */
  --r: 10px; /* the radius */

  --_f: calc(100%*var(--f)/(1 + var(--f)));
  --_a: calc(90deg*var(--f));

  width: 250px; /* image size */
  aspect-ratio: calc(1 + var(--f));
  object-fit: cover;
  clip-path: inset(0 var(--_f) 0 0 round var(--r));
  transform: perspective(400px) translateX(0px) rotateY(var(--_a));
  transition: .5s;
}
img:hover {
  clip-path: inset(0 0 0 var(--_f) round var(--r));
  transform: perspective(400px) translateX(calc(-1*var(--_f))) rotateY(calc(-1*var(--_a)));
}

I’ve rounded the edges of the clipped area slightly to make the effect a little more fancy. If you’re wondering why I didn’t use the border-radius property, it’s because the property doesn’t work well with clipped areas. Luckily, clip-path accepts a round value to get the same sort of rounded corners.

That’s it! We’re actually done with this neat hover effect on our image.

See the Pen 3D parallax effect on hover by Temani Afif.

You can adjust the parallax factor and the rotation angle, then work with the best image possible for using it in your own work. If you do use it, please show me your demos in the comments!

CSS 3D Rotation #

For this last demo, we will add depth to the image and transform it into a 3D box.

See the Pen 3D images with hover effect by Temani Afif.

For this one, I will skip the rotation part because it’s the same as what we just made in the last demo. Let’s focus instead on the 3D part, using the outline and clip-path properties. The following image illustrates how they come together to form a 3D box.

An outline surrounds the image (1), then is offset to cover the image (2) so that it can be clipped in the shape of a box (3)
An outline surrounds the image (1), then is offset to cover the image (2) so that it can be clipped in the shape of a box (3). (Large preview)

Here’s how that works. First, we add some padding to the top and the bottom of the image and apply an outline that is semi-transparent black.

Second, we apply a negative outline-offset so that the outline covers the image on the left and right sides but leaves the top and bottom alone:

img {
  --d: 18px;  /* depth */

  padding-block: var(--d);
  outline: var(--d) solid #0008;
  outline-offset: calc(-1 * var(--d));
}

Notice that I have created a variable, --d, that controls the thickness of the outline. This is what gives the image depth.

The last step is to add the clip-path. We need a polygon with eight points for that.

An image with the eight points of the clipped polygon shape
Showing the eight points of the clipped polygon shape. (Large preview)

The red points are fixed, and the green points are ones that we will animate to reveal the depth. I know it’s far from a 3D box, but this next visual, where we add the rotation, gives a better illustration.

The image starts with depth facing in one direction (left), then is rotated on hover to hide the depth for a flat appearance (center). We can change the direction of the depth as well (right)
The image starts with depth facing in one direction (left), then is rotated on hover to hide the depth for a flat appearance (center). We can change the direction of the depth as well (right). (Large preview)

Initially, the image is rotated with some perspective. The green points on the right are aligned with the red ones. Thus, we hide the outline on that side to keep it visible only on the left side. We have our 3D box with the depth on the left.

On hover, we move the green points on the left while rotating the image. Halfway through the animation, all the green points are aligned with the red ones, and the rotation angle is equal to 0deg, hiding the outline and giving the image a flat appearance.

Then, we continue the rotation, and the green points on the right move while the left ones remain in place. We get the same 3D effect but with the depth on the right side.

Bear with me because the next block of code is going to look really confusing at first. That’s due to a few new variables and the eight-point polygon we’re drawing on the clip-path property.

@property --_l {
  syntax: "<flength>";
  initial-value: 0px;
  inherits: true;
}
@property --_r {
  syntax: "<length>";
  initial-value: 0px;
  inherits: true;
}

img {
  --d: 18px;  /* depth */
  --a: 20deg; /* angle */
  --x: 10px;

  --_d: calc(100% - var(--d));
  --_l: 0px;
  --_r: 0px;

  clip-path: polygon(
    /* The two green points on the left */
    var(--_l) calc(var(--_d) - var(--x)),
    var(--_l) calc(var(--d)  + var(--x)),

    /* The two red points on the top */
    var(--d) var(--d),var(--_d) var(--d),

    /* The two green points on the right */
    calc(var(--_d) + var(--_r)) calc(var(--d)  + var(--x)),
    calc(var(--_d) + var(--_r)) calc(var(--_d) - var(--x)),

    /* The two red points on the bottom */
    var(--_d) var(--_d),var(--d) var(--_d)

    );
  transition: transform .3s, --_r .15s, --_l .15s .15s;
}

/* Update the points of the polygon on hover */
img:hover{
  --_l: var(--d);
  --_r: var(--d);
  --_i: -1;
  transition-delay: 0s, .15s, 0s;
}

I’ve used comments to help explain what the code is doing. Notice I am using the variables --_l and --_r to define the position of the green points. I animate those variables from 0 to the depth (--d) value. The @property declarations at the top allow us to animate the variables by specifying the type of values they are (<length>).

Note: Not all browsers currently support @property. So, I’ve added a fallback in the demo with a slightly different animation.

After the polygon is drawn on the clip-path property, the next thing the code does is apply a transition that handles the rotation. The full rotation lasts .3s, so the green points need to transition at half that duration (.15s). On hover, the polygon points on the left move immediately (0s) while the right points move at half the duration (courtesy of a .15s delay). When we leave the hovered state, we use different delays because we need the right points to move immediately (0s) while the left points move at half the duration.

What’s up with that --x variable, right? If you check the first image that I provided to illustrate the clip-path points, you will notice that the green points are slightly shifted from the top and bottom edges, which is logical to simulate the 3D effect. The --x variable controls how much shifting takes place, but the math behind it is a bit complex and not easy to express in CSS. So, we update it manually based on each case until we get a value that feels right.

That gives us our final result!

See the Pen 3D images with hover effect by Temani Afif.

Wrapping Up #

I hope you enjoyed — and perhaps were even challenged by — this exploration of CSS 3D image effects. We worked with a whole bunch of advanced CSS features, including masks, clipping, gradients, transitions, and calculations, to make some pretty incredible hover effects for images that you certainly don’t see every day.

And we did it in a way that only needed one line of HTML. No divs. No classes or IDs. No pseudo-elements. Just a single <img> tag is all we need. Yes, it’s true that more markup may have made the CSS less complex, but the fact that it relies on a plain HTML element means the CSS can be used more broadly. CSS is powerful enough to do all of this on a single element!

I’ve written extensively about advanced CSS styles for images. If you’re looking for more ideas and inspiration, I encourage you to check out the following articles I’ve published:

I also run a site called CSS Tip that explores even more fancy effects — subscribe to the RSS feed to keep up with the experiments I do over there!