现代CSS代码片段:停止像在2015年一样编写CSS
Modern CSS Code Snippets: Stop writing CSS like it's 2015

原始链接: https://modern-css.com

## 现代 CSS:告别旧技巧 Modern.css 是一个资源,致力于展示最新的 CSS 特性,并为较旧、常常需要变通的技巧提供简洁、原生的替代方案。该资源已更新至 2026 年,提供了 **56 个代码片段**,展示了如何用更简单、更高效的代码实现相同的结果。 该网站重点介绍了 **布局、动画、工作流程、排版和颜色** 等多个方面的改进。例如,居中元素不再需要复杂的 `position` 和 `transform` 属性——简单的 `display: grid; place-items: center;` 即可满足需求。 同样,滚动链接动画和对话框可以在 *无需* JavaScript 的情况下实现。 Modern.css 跟踪 **26 个 CSS 特性**,并提供浏览器兼容性信息。它旨在通过消除记住过时解决方案的需求,从而简化开发,并提供更易于维护和性能更高的 CSS 方法。每周简报会将一个“旧方法到新方法”的比较直接发送到您的收件箱。

黑客新闻 新 | 过去 | 评论 | 提问 | 展示 | 招聘 | 提交 登录 现代 CSS 代码片段:停止像在 2015 年一样编写 CSS (modern-css.com) 17 分,eustoria 发表于 2 小时前 | 隐藏 | 过去 | 收藏 | 讨论 帮助 指南 | 常见问题 | 列表 | API | 安全 | 法律 | 申请 YC | 联系方式 搜索:
相关文章

原文
Updated for 2026

Stop writing CSS

like it's 2015.

Modern CSS code snippets, side by side with the old hacks they replace. Every technique you still Google has a clean, native replacement now.

Old
.child {

position: absolute;

top: 50%;

left: 50%;

transform: translate(-50%,-50%);

}
Modern
.parent {

display: grid;

place-items: center;

}



/* child needs nothing. */

All comparisons

56 snippets
Browser compatibility:
Workflow
Advanced

Range style queries without multiple blocks

Old /* Multiple style() blocks */

@container style(--p: 51%) {}

@container style(--p: 52%) {}

/* ...for each value */
Modern @container style(

--progress > 50%

) {

.bar { ... }

}
see modern →
Animation
Intermediate

Sticky & snapped element styling without JavaScript

Old window.addEventListener(

'scroll', () => {

/* check position */

});
Modern @container scroll-state(

stuck: top

) {

.header { ... }

}
see modern →
Workflow
Intermediate

Typed attribute values without JavaScript

Old // JS reading dataset

el.style.width =

el.dataset.pct + '%';
Modern .bar {

width: attr(

data-pct type()

);

}
see modern →
Workflow
Intermediate

Inline conditional styles without JavaScript

Old // JavaScript toggling

el.classList.toggle(

'primary', isPrimary

);
Modern .btn {

background: if(

style(--variant: primary):

blue; else: gray

);

}
see modern →
Workflow
Intermediate

Reusable CSS logic without Sass mixins

Old // Sass function

@function fluid($min, $max) {

@return clamp(...);

}
Modern @function --fluid(

--min, --max

) {

@return clamp(...);

}
see modern →
Layout
Beginner

Corner shapes beyond rounded borders

Old .card {

clip-path: polygon(

... /* 20+ points */

);

}
Modern .card {

border-radius: 2em;

corner-shape: squircle;

}
see modern →
Animation
Advanced

Responsive clip paths without SVG

Old .shape {

clip-path: path(

'M0 200 L100 0...'

);

}
Modern .shape {

clip-path: shape(

from 0% 100%, ...

);

}
see modern →
Selector
Intermediate

Scroll spy without IntersectionObserver

Old const observer = new

IntersectionObserver(cb);

/* 15+ lines of JS */
Modern nav a:target-current {

color: var(--accent);

}
see modern →
Layout
Beginner

Filling available space without calc workarounds

Old .full {

width: calc(100% - 40px);

/* or width: 100% and overflow */

}
Modern .full {

width: stretch;

}

/* fills container, keeps margins */
see modern →
Animation
Intermediate

Staggered animations without nth-child hacks

Old li:nth-child(1) { --i: 0; }

li:nth-child(2) { --i: 1; }

li:nth-child(3) { --i: 2; }

/* repeat for every item… */
Modern li {

transition-delay:

calc(0.1s * (sibling-index() - 1));

}
see modern →
Layout
Advanced

Carousel navigation without a JavaScript library

Old // Swiper.js or Slick carousel

new Swiper('.carousel', {

navigation: { /* … */ },

pagination: { /* … */ },

});
Modern .carousel::scroll-button(right) {

content: "➡";

}

.carousel li::scroll-marker {

content: '';

}
see modern →
Typography
Beginner

Vertical text centering without padding hacks

Old .btn {

padding: 10px 20px;

/* looks off-center, tweak top/bottom */

padding-top: 8px; /* hack */

}
Modern h1, button {

text-box: trim-both cap alphabetic;

}

/* true optical centering */
see modern →
Layout
Intermediate

Hover tooltips without JavaScript events

Old // JS: mouseenter + mouseleave

btn.addEventListener('mouseenter',

() => showTooltip())

/* + focus, blur, positioning */
Modern interestfor="tip">Hover me

id="tip" popover=hint>

Tooltip content

see modern →
Layout
Beginner

Modal controls without onclick handlers

Old onclick="

document.querySelector('#dlg')

.showModal()">Open
Modern commandfor="dlg"

command="show-modal">Open

id="dlg">...
see modern →
Layout
Beginner

Dialog light dismiss without click-outside listeners

Old // JS: listen for click on ::backdrop

dialog.addEventListener('click',

(e) => { /* check bounds */ })
Modern closedby="any">

Click outside to close



/* no JS listeners */
see modern →
Layout
Intermediate

Customizable selects without a JavaScript library

Old // Select2 or Choices.js

new Choices('#my-select');

/* rebuilds entire DOM */
Modern select,

select ::picker(select) {

appearance: base-select;

}
see modern →
Color
Intermediate

Vivid colors beyond sRGB

Old .hero {

color: rgb(200, 80, 50);

}

/* sRGB only, washed on P3 */
Modern .hero {

color: oklch(0.7 0.25 29);

}

/* or color(display-p3 1 0.2 0.1) */
see modern →
Color
Advanced

Color variants without Sass functions

Old /* Sass: lighten($brand, 20%), darken($brand, 10%) */

.btn { background: #e0e0e0; }
Modern .btn {

background: oklch(from var(--brand) calc(l + 0.2) c h);

}
see modern →
Typography
Beginner

Multiline text truncation without JavaScript

Old /* JS: slice text by chars/words, add "..." */

.card-title { overflow: hidden; }
Modern .card-title {

display: -webkit-box;

-webkit-line-clamp: 3;

line-clamp: 3;

}
see modern →
Typography
Beginner

Drop caps without float hacks

Old .drop-cap::first-letter {

float: left;

font-size: 3em; line-height: 1;

}
Modern .drop-cap::first-letter {

initial-letter: 3;

}
see modern →
Layout
Beginner

Positioning shorthand without four properties

Old .overlay {

top: 0; right: 0;

bottom: 0; left: 0;

}
Modern .overlay {

position: absolute;

inset: 0;

}
see modern →
Workflow
Intermediate

Lazy rendering without IntersectionObserver

Old // JS IntersectionObserver

new IntersectionObserver(

(entries) => { /* render */ }

).observe(el);
Modern .section {

content-visibility: auto;

contain-intrinsic-size: auto 500px;

}
see modern →
Layout
Beginner

Dropdown menus without JavaScript toggles

Old .menu { display: none; }

.menu.open { display: block; }

/* + JS: click, clickOutside, ESC, aria */
Modern button[popovertarget=menu] { }

#menu[popover] {

position: absolute;

}
see modern →
Layout
Advanced

Tooltip positioning without JavaScript

Old /* Popper.js / Floating UI: compute rect,

position: fixed, update on scroll */

.tooltip { position: fixed; }
Modern .trigger { anchor-name: --tip; }

.tooltip {

position-anchor: --tip;

top: anchor(bottom);

}
see modern →
Workflow
Advanced

Scoped styles without BEM naming

Old // BEM: .card__title, .card__body

.card__title { … }

.card__body { … }

// or CSS Modules / styled-components */
Modern @scope (.card) {

.title { font-size: 1.25rem; }

.body { color: #444; }

}

/* .title only inside .card */
see modern →
Workflow
Advanced

Typed custom properties without JavaScript

Old // --hue was a string, no animation

:root { --hue: 0; }

hsl(var(--hue), …) /* no interpolation */
Modern @property --hue {

syntax: "";

inherits: false;

initial-value: 0deg;

}

/* animatable, validated */
see modern →
Animation
Beginner

Independent transforms without the shorthand

Old .icon { transform: translateX(10px) rotate(45deg) scale(1.2); }

/* change one = rewrite all */
Modern .icon {

translate: 10px 0;

rotate: 45deg;

scale: 1.2;

}

/* animate any one without touching the rest */
see modern →
Animation
Intermediate

Animating display none without workarounds

Old // wait for transitionend then display:none

el.addEventListener('transitionend', …)

visibility + opacity + pointer-events
Modern .panel { transition: opacity .2s, overlay .2s;

transition-behavior: allow-discrete; }

.panel.hidden { opacity: 0; display: none; }

/* no JS wait or visibility hack */
see modern →
Animation
Intermediate

Entry animations without JavaScript timing

Old // add class after paint

requestAnimationFrame(() => {

el.classList.add('visible');

});
Modern .card { transition: opacity .3s, transform .3s; }

.card { @starting-style { opacity: 0; transform: translateY(10px); } }

/* no rAF/setTimeout */
see modern →
Animation
Advanced

Page transitions without a framework

Old // Barba.js or React Transition Group

Barba.init({ … })

transition hooks + duration state
Modern document.startViewTransition(() => updateDOM());

.hero { view-transition-name: hero; }

/* no Barba, no React TG */
see modern →
Layout
Intermediate

Scroll snapping without a carousel library

Old // Slick, Swiper, or scroll/touch JS

$('.carousel').slick({ … })

touchstart / scroll handlers
Modern .carousel { scroll-snap-type: x mandatory; }

.carousel > * { scroll-snap-align: start; }

/* no lib, no touch handlers */
see modern →
Typography
Beginner

Balanced headlines without manual line breaks

Old // manual
or Balance-Text.js


h1 { text-align: center; }

.balance-text /* JS lib */
Modern h1, h2 {

text-wrap: balance;

}

/* no br or JS */
see modern →
Typography
Beginner

Font loading without invisible text

Old @font-face { ... }

/* Default: invisible text until load */
Modern @font-face {

font-family: "MyFont";

font-display: swap;

}
see modern →
Typography
Intermediate

Multiple font weights without multiple files

Old @font-face { font-weight: 400; }

@font-face { font-weight: 700; }

/* 4+ files */
Modern @font-face {

font-family: "MyVar";

src: url("MyVar.woff2");

font-weight: 100 900;

}
see modern →
Workflow
Beginner

Dark mode defaults without extra CSS

Old @media (prefers-color-scheme: dark) {

input, select, textarea { ... }

}
Modern :root {

color-scheme: light dark;

}
see modern →
Color
Intermediate

Dark mode colors without duplicating values

Old @media (prefers-color-scheme: dark) {

color: #eee;

}
Modern color: light-dark(#111, #eee);

color-scheme: light dark;
see modern →
Selector
Intermediate

Low-specificity resets without complicated selectors

Old .reset ul, .reset ol { ... }

/* or (0,0,1) specificity, still wins */
Modern :where(ul, ol) {

margin: 0;

padding-inline-start: 1.5rem;

}
see modern →
Layout
Intermediate

Direction-aware layouts without left and right

Old margin-left: 1rem;

padding-right: 1rem;

[dir="rtl"] .box { margin-right: ... }
Modern margin-inline-start: 1rem;

padding-inline-end: 1rem;

border-block-start: 1px solid;
see modern →
Layout
Beginner

Naming grid areas without line numbers

Old float: left; /* clearfix, margins */

grid-column: 1 / 3;

grid-row: 2;
Modern .layout {

display: grid;

grid-template-areas: "header header" "sidebar main" "footer footer";

}
see modern →
Layout
Advanced

Aligning nested grids without duplicating tracks

Old .child-grid {

grid-template-columns: 1fr 1fr 1fr;

/* duplicate parent tracks */

}
Modern .child-grid {

display: grid;

grid-template-columns: subgrid;

}
see modern →
Layout
Intermediate

Modal dialogs without a JavaScript library

Old .overlay { position: fixed; z-index: 999; }

/* + JS: open/close, ESC, focus trap */
Modern dialog {

padding: 1rem;

}

dialog::backdrop { background: rgb(0 0 0 / .5); }
see modern →
Color
Beginner

Styling form controls without rebuilding them

Old appearance: none;

// + 20+ lines of custom box/border/background
Modern input[type="checkbox"],

input[type="radio"] {

accent-color: #7c3aed;

}
see modern →
Selector
Beginner

Grouping selectors without repetition

Old .card h1, .card h2, .card h3, .card h4 {

margin-bottom: 0.5em;

}
Modern .card :is(h1, h2, h3, h4) {

margin-bottom: 0.5em;

}
see modern →
Selector
Beginner

Focus styles without annoying mouse users

Old :focus { outline: 2px solid blue; }

// Shows on mouse click too, or people remove it (a11y fail)
Modern :focus-visible {

outline: 2px solid var(--focus-color);

}
see modern →
Workflow
Intermediate

Controlling specificity without !important

Old .card .title { ... }

.page .card .title { ... }

.page .card .title.special { color: red !important; }
Modern @layer base, components, utilities;

@layer utilities { .mt-4 { margin-top: 1rem; } }
see modern →
Workflow
Beginner

Theme variables without a preprocessor

Old // Sass: $primary: #7c3aed;

// Compiles to static #7c3aed

.btn { background: $primary; }
Modern :root {

--primary: #7c3aed;

}

.btn { background: var(--primary); }
see modern →
Typography
Intermediate

Fluid typography without media queries

Old h1 { font-size: 1rem; }

@media (min-width: 600px) { h1 { font-size: 1.5rem; } }

@media (min-width: 900px) { h1 { font-size: 2rem; } }
Modern h1 {

font-size: clamp(1rem, 2.5vw, 2rem);

}
see modern →
Layout
Beginner

Spacing elements without margin hacks

Old .grid > * { margin-right: 16px; }

.grid > *:last-child { margin-right: 0; }
Modern .grid {

display: flex;

gap: 16px;

}
see modern →
Layout
Beginner

Aspect ratios without the padding hack

Old .wrapper { padding-top: 56.25%; position: relative; }

.inner { position: absolute; inset: 0; }
Modern .video-wrapper {

aspect-ratio: 16 / 9;

}
see modern →
Layout
Beginner

Sticky headers without JavaScript scroll listeners

Old // JS: scroll listener + getBoundingClientRect

// then add/remove .fixed class

.header.fixed { position: fixed; }
Modern .header {

position: sticky;

top: 0;

}
see modern →
Animation
Advanced

Scroll-linked animations without a library

Old // JS + IntersectionObserver

observer.observe(el)

el.style.opacity = …
Modern animation-timeline: view();

animation-range: entry;

/* pure CSS, GPU-accelerated */
see modern →
Workflow
Beginner

Nesting selectors without Sass or Less

Old // requires Sass compiler

.nav {

& a { color: #888; }

}
Modern .nav {

& a { color: #888; }

}

/* plain .css, no build */
see modern →
Layout
Intermediate

Responsive components without media queries

Old @media (max-width: 768px) {

.card { … }

}

/* viewport, not container */
Modern @container (width < 400px) {

.card { flex-direction: column; }

}
see modern →
Colors
Intermediate

Mixing colors without a preprocessor

Old // Sass required

$blend: mix(

$blue, $pink, 60%);
Modern background: color-mix(

in oklch, #3b82f6,

#ec4899);
see modern →
Selectors
Intermediate

Selecting parent elements without JavaScript

Old // JavaScript required

el.closest('.parent')

.classList.add(…)
Modern .card:has(img) {

grid-template: auto 1fr;

}
see modern →
Layout
Beginner

Centering elements without the transform hack

Old position: absolute;

top: 50%; left: 50%;

transform: translate(-50%,-50%);
Modern .parent {

display: grid;

place-items: center;

}
see modern →
56
Snippets
26
CSS Features Tracked
3
Articles
0
Dependencies
ESC
联系我们 contact @ memedata.com