Author: Ahmad Shadeed
Translator: Front-end Xiaozhi Source: isadeed
A new series is out: Vue2 and Vue3 Tips Booklet
Wechat search [Great Relocation to the World], I will share with you the front-end industry trends, learning methods, etc. as soon as possible.
This article GitHub https://github.com/qq449245884/xiaozhi has been included, there are complete test sites, materials and my series of articles for interviews with first-line manufacturers.
Many times we wish there was a way to avoid a certain CSS issue or behavior from happening. We know that web content is dynamic and things on a web page can change, increasing the likelihood of CSS issues or strange behavior.
Defensive CSS is a collection of snippets that help me write protected CSS. In other words, there will be more bugs in the future.
1. Flexbox Package
CSS flexbox is one of the most useful CSS layout features out there. Add display: flex
to a wrapper to sort the children next to each other.
The problem is that those subitems are not wrapped into a new row by default when there is not enough space. We need to use flex-wrap: wrap
to change this behavior.
Below is a typical example.
.options-list {
display: flex;
}
Horizontal scrolling occurs when there is less space. This should be expected and is not actually a "problem".
.options-list {
display: flex;
flex-wrap: wrap;
}
When using flexbox
, the general rule of thumb is to allow wraps unless you want a rolling wrap. That's another story, but try to use flex-wrap
to avoid unexpected layout behavior (in our case, horizontal scrolling).
2. Spacing
We developers need to consider different content lengths. This means, spacing should be added to the component even if it doesn't appear to be needed.
In this example, we have a section
title and an action button on the right. For now, it looks fine. But what would happen if the title were longer?
Notice how the text is too close to the button? Here, you might consider multiple line wrapping, but for now, let's focus on spacing.
If the title has spaces and text is truncated, we don't see such a problem.
.section__title {
margin-right: 1rem;
}
3. Long Content
When building layouts, it's important to take long content into account. As you saw earlier, chapter titles are truncated when they are too long. This is optional, but for some UIs it's important to take this into account.
To me, this is a defensive CSS approach. It's good to fix the "problem" before it actually happens.
Here's a list of names that look perfect right now
However, since this is user-generated content, we need to be careful how we defend the layout in case some content is too long. Please see the image below:
In this layout, consistency is very important. To achieve this, we can simply truncate the name using text-overflow
and its friends.
4. Prevent images from being stretched or compressed
In the case where the image aspect ratio cannot be controlled, if the image uploaded by the user does not match the aspect ratio, it is best to consider and provide a solution in advance.
In the example below, we have a card component with a photo. It looks good.
When the user uploads an image of a different size, it will be stretched. This is not a good thing. See how the image is stretched!
The easiest fix is to use CSS object-fit
.
.card__thumb {
object-fit: cover;
}
On a project level, I tend to add object-fit
for all images to avoid unexpected results.
5. Lock Scroll Links
Have you ever opened a modal and started scrolling, then when you reach the end and continue scrolling, the content (body element) below the modal scrolls? This is called a rolling chain.
By default, when touching the top or bottom of the page (or other scrollable area), mobile browsers tend to provide a "bottom out" effect or even a page refresh. You may also find that when a dialog has scrollable content, once you scroll to the borders of the dialog, the page content below the dialog also starts to scroll - this is called a "scroll chain". .
Over the past few years, there have been some hacks to achieve this, but now, we just use CSS, thanks to the overscroll-behavior
CSS property.
In the image below, you can see the default scroll link behavior.
To avoid this in advance, we can add it to any component that needs scrolling (eg: chat component, mobile menu...etc). The nice thing about this property is that it doesn't have an effect until there is scrolling.
.modal__content {
overscroll-behavior-y: contain;
overflow-y: auto;
}
6. CSS Variable Fallback
CSS variables are used more and more in web design. We can apply a way to use CSS variable values in a way that doesn't break the experience in case they are null for some reason.
Especially useful when entering the value of CSS variables via JS. Below is an example:
.message__bubble {
max-width: calc(100% - var(--actions-width));
}
The variable --actions-width
is used in the calc()
function and its value comes from JS. Suppose JS fails for some reason, what happens? max-width
will be calculated as zero.
We can avoid this earlier by adding a fallback value to var()
.
.message__bubble {
max-width: calc(100% - var(--actions-width, 70px));
}
This way, if the variable is not defined, the fallback (70px)
is used. This approach can be used in situations where variables may fail.
7. Use a fixed width or height
One of the common things that breaks a layout is using a fixed width or height for an element that has content of varying lengths.
fixed height
I often see the main content section has a fixed height and the content is larger than this height, which leads to broken layout. As follows:
.main {
height: 350px;
}
To avoid this, use min-height
instead of height
:
fixed width
Have you ever seen a button with its label too close to the left and right edges? This is due to the use of a fixed width.
.button {
width: 100px;
}
If the button's label is larger than 100px
, it will be close to the edge. If it's too long, the text will leak out. this is not good!
To fix this, we can simply replace ---e1cd62cabdd426001a873a4974c3ee8d min-width
with width
.
.button {
min-width: 100px;
}
8. Forget the background-Repeat
Many times, when using a large image as a background, we tend to forget to consider how the design will look when viewed on a large screen. The background will repeat by default.
This is mostly not seen on laptop screens, but is common on larger screens.
To avoid this behavior in advance, make sure to use reset background-repeat
.
.hero {
background-image: url('..');
background-repeat: no-repeat;
}
9. Vertical Media Queries
Sometimes, we're tempted to build a component and test it only by adjusting the width of the browser. Testing against browser height can reveal some interesting issues.
Here's an example that I've seen multiple times. We have a component with primary and secondary links. Secondary links should be at the very bottom of the narration section.
Consider the following example. The primary and secondary navigation looks fine. In the example I saw, the developer added position: sticky
to the secondary navigation so that it would stick to the bottom.
However, if the height of the browser is small, the bug comes. Notice how the two navigations overlap.
By using CSS vertical media queries, we can avoid this problem.
@media (min-height: 600px) {
.aside__secondary {
position: sticky;
bottom: 0;
}
}
This way, the secondary nav will be stuck to the bottom only if the viewport height is greater than or equal to 600px
. Much better, right?
There are probably better ways to achieve this behavior (like using margin-auto
), but focus on vertical queries for this example.
10. Use justify-content:space-between
In a container of flex
we might use justify-content
to have some spacing between subitems. The layout will look fine if there is a certain number of sub-items. However, when they increase or decrease, the layout will look weird.
Consider the following example:
We have a flex container with four items. The spacing between each item is not gap
or margin
, it exists because the container has justify-content: space-between
.
.wrapper {
display: flex;
flex-wrap: wrap;
justify-content: space-between;
}
When the number of items is less than 4, the following happens:
This is not a good thing. There are different solutions for this:
- margin
- flexbox gap (use with caution)
- padding (applies to each child element's parent element)
- Add empty elements as spacers.
For simplicity, I use gap
.
.wrapper {
display: flex;
flex-wrap: wrap;
gap: 1rem;
}
11. Text on pictures
When placing text over an image, you must take into account the fact that the image fails to load. What the text will look like. Below is an example:
The text appears to be readable, but when the image fails to load it becomes poorly readable.
We solved this easily by adding a background color to the <img>
element. This background is only shown if the image fails to load.
12. Be careful with fixed values in CSS grids
Suppose we have a grid containing aside
and main
. CSS looks like this:
.wrapper {
display: grid;
grid-template-columns: 250px 1fr;
gap: 1rem;
}
This can be problematic on small viewport sizes due to lack of space. To avoid problems like this, be sure to use media queries when using the above CSS grid.
@media (min-width: 600px) {
.wrapper {
display: grid;
grid-template-columns: 250px 1fr;
gap: 1rem;
}
}
13. Show scrollbars only when needed
We can control showing scrollbars or not just in case of long content. Nonetheless, it is strongly recommended to use auto
as the value for overflow
. Consider the following example:
Note that there is a scrollbar visible even if the content is short. This is not good for a user interface. As a user, it's confusing to see scrollbars when you don't need them.
.element {
overflow-y: auto;
}
With overflow-y: auto
, the scrollbar is only visible when the content is long. Otherwise, it is not displayed.
14. Scrollbar Gutter
Another thing to do with scrolling is Scrollbar Gutter
. Taking the previous example as an example, adding a scrollbar will cause the layout to shift when the content gets longer. The layout movement happens because a space is reserved for the scroll bar.
The Scrollbar Gutter is the space between the inner border edge and the outer padding edge. For classic scrollbars, the size of the Scrollbar Gutter is the same as the width of the scrollbar. These scroll bars are usually opaque and take up some space from adjacent content.
Please see the image below:
Notice how it shifts as the content gets longer due to the scrollbar being shown. We can avoid this behavior by using the scrollbar-gutter
attribute.
.element {
scrollbar-gutter: stable;
}
15. Minimum Content Size in CSS Flexbox
If the text elements or images in a flex item are larger or longer than the item itself, the browser will not shrink them. This is the default behavior of Flexbox. Consider the following example:
.card {
display: flex;
}
When the title has a very long word, it is not wrapped into a new line.
Even if we use overflow-wrap: break-word
, it won't work.
.card__title {
overflow-wrap: break-word;
}
To change this default behavior, we need to set the flex
project's min-width
to 0
. This is because the default value of ---f2d6f877c5a1d79f58479cb57daeb648 min-width
is auto
and overflow occurs.
.card__title {
overflow-wrap: break-word;
min-width: 0;
}
The same applies to the flex-direction:column
layout, and the corresponding use min-height: 0
.
16. Minimum Content Size in CSS Grid
Similar to flexbox, CSS grid has a default minimum content size for its children, which is auto
. This means that if an element is larger than the grid item, it will overflow.
In the above example, we have a carousel
in the main section.
<div class="wrapper">
<main>
<section class="carousel"></section>
</main>
<aside></aside>
</div>
@media (min-width: 1020px) {
.wrapper {
display: grid;
grid-template-columns: 1fr 248px;
grid-gap: 40px;
}
}
.carousel {
display: flex;
overflow-x: auto;
}
Since carousel
is a flex layout, when the content exceeds, it will not wrap by default, so horizontal scrolling will occur.
To solve this problem, we have three different solutions:
- Use
minmax()
- Apply
min-width
to grid item - Add
overflow: hidden
to the network
As a defensive CSS mechanism, I would choose the first one, which is to use the minmax()
function.
@media (min-width: 1020px) {
.wrapper {
display: grid;
grid-template-columns: minmax(0, 1fr) 248px;
grid-gap: 40px;
}
}
Auto Fit Vs Auto Fill
When using the CSS Grid minmax()
function, it is important to decide whether to use the auto-fit
or auto-fill
keyword. Improper use can lead to unexpected results.
When using the minmax()
function, the auto-fit
keyword will expand the grid items to fill the available space. And auto-fill
will preserve the available space without changing the width of the grid items.
That said, using auto-fit
may cause grid items to be too wide, especially when they are smaller than expected. Consider the following example.
The bugs that may exist in editing cannot be known in real time. In order to solve these bugs afterwards, a lot of time is spent on log debugging. By the way, here is a useful bug monitoring tool , Fundebug .
Forgive: https://ishadeed.com/article/defensive-css/
comminicate
If you have dreams and dry goods, you can search for [Great Move to the World] on WeChat and pay attention to this Shawanzhi who is still washing dishes in the early hours of the morning.
This article GitHub https://github.com/qq449245884/xiaozhi has been included, there are complete test sites, materials and my series of articles for interviews with first-line manufacturers.
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。