modern
.css
Snippets
Articles
What's New
Resources
Search…
Ctrl
K
Home
/
Layout
Layout
Layout comparisons
20 old vs modern layout CSS techniques, side by side.
Layout
Beginner
Corner shapes beyond rounded borders
Modern
.card
{
border-radius
:
2em
;
corner-shape
:
squircle
;
}
Old
.card
{
clip-path
:
polygon
(
...
/* 20+ points */
);
}
hover to see old →
Layout
Beginner
Filling available space without calc workarounds
Modern
.full
{
width
:
stretch
;
}
/* fills container, keeps margins */
Old
.full
{
width
:
calc
(
100%
-
40px
);
/* or width: 100% and overflow */
}
hover to see old →
Layout
Advanced
Carousel navigation without a JavaScript library
Modern
.carousel
::scroll-button(right)
{
content
:
"➡"
;
}
.carousel li
::scroll-marker
{
content
:
''
;
}
Old
// Swiper.js or Slick carousel
new
Swiper
(
'.carousel'
, {
navigation
: {
/* … */
},
pagination
: {
/* … */
},
});
hover to see old →
Layout
Intermediate
Hover tooltips without JavaScript events
Modern
<button
interestfor
=
"tip"
>
Hover me
</button>
<div
id
=
"tip"
popover
=
hint
>
Tooltip content
</div>
Old
// JS: mouseenter + mouseleave
btn
.
addEventListener
(
'mouseenter'
,
() =>
showTooltip
())
/* + focus, blur, positioning */
hover to see old →
Layout
Beginner
Modal controls without onclick handlers
Modern
<button
commandfor
=
"dlg"
command
=
"show-modal"
>
Open
</button>
<dialog
id
=
"dlg"
>
...
</dialog>
Old
<button
onclick
=
"
document
.
querySelector
(
'#dlg'
)
.
showModal
()
"
>
Open
</button>
hover to see old →
Layout
Beginner
Dialog light dismiss without click-outside listeners
Modern
<dialog
closedby
=
"any"
>
Click outside to close
</dialog>
/* no JS listeners */
Old
// JS: listen for click on ::backdrop
dialog
.
addEventListener
(
'click'
,
(e) => {
/* check bounds */
})
hover to see old →
Layout
Intermediate
Customizable selects without a JavaScript library
Modern
select
,
select
::picker(select)
{
appearance
:
base-select
;
}
Old
// Select2 or Choices.js
new
Choices
(
'#my-select'
);
/* rebuilds entire DOM */
hover to see old →
Layout
Beginner
Positioning shorthand without four properties
Modern
.overlay
{
position
:
absolute
;
inset
:
0
;
}
Old
.overlay
{
top
:
0
;
right
:
0
;
bottom
:
0
;
left
:
0
;
}
hover to see old →
Layout
Beginner
Dropdown menus without JavaScript toggles
Modern
button
[
popovertarget
=
menu
] { }
#menu
[
popover
] {
position
:
absolute
;
}
Old
.menu
{
display
:
none
; }
.menu.open
{
display
:
block
; }
/* + JS: click, clickOutside, ESC, aria */
hover to see old →
Layout
Advanced
Tooltip positioning without JavaScript
Modern
.trigger
{
anchor-name
:
--tip
; }
.tooltip
{
position-anchor
:
--tip
;
top
:
anchor(bottom)
;
}
Old
/* Popper.js / Floating UI: compute rect,
position: fixed, update on scroll */
.tooltip
{
position
:
fixed
; }
hover to see old →
Layout
Intermediate
Scroll snapping without a carousel library
Modern
.carousel
{
scroll-snap-type
:
x mandatory
; }
.carousel > *
{
scroll-snap-align
:
start
; }
/* no lib, no touch handlers */
Old
// Slick, Swiper, or scroll/touch JS
$
(
'.carousel'
).
slick
({ … })
touchstart
/
scroll
handlers
hover to see old →
Layout
Intermediate
Direction-aware layouts without left and right
Modern
margin-inline-start
:
1rem
;
padding-inline-end
:
1rem
;
border-block-start
:
1px solid
;
Old
margin-left
:
1rem
;
padding-right
:
1rem
;
[dir="rtl"
]
.box
{
margin-right
: ... }
hover to see old →
Layout
Beginner
Naming grid areas without line numbers
Modern
.layout
{
display
:
grid
;
grid-template-areas
:
"header header" "sidebar main" "footer footer"
;
}
Old
float
:
left
;
/* clearfix, margins */
grid-column
:
1 / 3
;
grid-row
:
2
;
hover to see old →
Layout
Advanced
Aligning nested grids without duplicating tracks
Modern
.child-grid
{
display
:
grid
;
grid-template-columns
:
subgrid
;
}
Old
.child-grid
{
grid-template-columns
:
1fr 1fr 1fr
;
/* duplicate parent tracks */
}
hover to see old →
Layout
Intermediate
Modal dialogs without a JavaScript library
Modern
dialog
{
padding
:
1rem
;
}
dialog::backdrop
{
background
:
rgb
(0 0 0 / .5); }
Old
.overlay
{
position
:
fixed
;
z-index
:
999
; }
/* + JS: open/close, ESC, focus trap */
hover to see old →
Layout
Beginner
Spacing elements without margin hacks
Modern
.grid
{
display
:
flex
;
gap
:
16px
;
}
Old
.grid
> *
{
margin-right
:
16px
; }
.grid
> *:last-child
{
margin-right
:
0
; }
hover to see old →
Layout
Beginner
Aspect ratios without the padding hack
Modern
.video-wrapper
{
aspect-ratio
:
16 / 9
;
}
Old
.wrapper
{
padding-top
:
56.25%
;
position
:
relative
; }
.inner
{
position
:
absolute
;
inset
:
0
; }
hover to see old →
Layout
Beginner
Sticky headers without JavaScript scroll listeners
Modern
.header
{
position
:
sticky
;
top
:
0
;
}
Old
// JS: scroll listener + getBoundingClientRect
// then add/remove .fixed class
.header.fixed
{
position
:
fixed
; }
hover to see old →
Layout
Intermediate
Responsive components without media queries
Modern
@container
(
width
<
400px
) {
.card
{
flex-direction
:
column
; }
}
Old
@media
(
max-width
:
768px
) {
.card
{ … }
}
/* viewport, not container */
hover to see old →
Layout
Beginner
Centering elements without the transform hack
Modern
.parent
{
display
:
grid
;
place-items
:
center
;
}
Old
position
:
absolute
;
top
:
50%
;
left
:
50%
;
transform
:
translate(-50%,-50%)
;
hover to see old →
Other categories
Animation
8 snippets
Color
5 snippets
Selector
5 snippets
Typography
7 snippets
Workflow
11 snippets
ESC