Centrar qualsevol cosa
Funciona a totsDues línies i centrat en els dos eixos. Serveix igual per a una icona que per a un modal.
.centro {
display: grid;
place-items: center;
}El que copio una vegada i una altra de projecte en projecte. Cada recepta té la demo funcionant al costat: si al teu navegador no es veu, és que encara no ho suporta.
Dues línies i centrat en els dos eixos. Serveix igual per a una icona que per a un modal.
.centro {
display: grid;
place-items: center;
}Tantes columnes com hi càpiguen, sense media queries. El min() evita que surti en mòbils estrets.
.rejilla {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(min(100%, 12rem), 1fr));
gap: 1rem;
}Amb poc contingut el peu no es queda surant a mitja pantalla. dvh té en compte la barra del navegador del mòbil.
body {
min-height: 100dvh;
display: grid;
grid-template-rows: auto 1fr auto;
}S'ha acabat el truc del padding-top: 56.25%. La imatge és quadrada i es veu en 16:9: object-fit: cover la retalla en lloc de deformar-la (va en img o video, en un div no fa res).
.portada {
aspect-ratio: 16 / 9;
width: 100%;
object-fit: cover;
}El component canvia segons l'espai que té, no segons la pantalla. Arrossega la cantonada de la caixa per veure-ho.
.tarjeta-wrap { container-type: inline-size; }
.tarjeta { display: grid; gap: 1rem; }
@container (min-width: 22rem) {
.tarjeta { grid-template-columns: 6rem 1fr; }
}Títols de longitud diferent i tot i així tots els botons a la mateixa alçada.
.tarjetas {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(9rem, 1fr));
gap: 1rem;
}
.tarjetas > * {
display: grid;
grid-row: span 3;
grid-template-rows: subgrid;
}scroll-snap fa que cada targeta encaixi en deixar-la anar. Amb el dit o amb el trackpad.
.carrusel {
display: flex;
gap: 1rem;
overflow-x: auto;
scroll-snap-type: x mandatory;
overscroll-behavior-x: contain;
}
.carrusel > * {
flex: 0 0 80%;
scroll-snap-align: center;
}Amb una capçalera fixa, el títol on saltes queda tapat. scroll-margin el baixa el just.
html { scroll-behavior: smooth; }
:target,
h2[id] {
scroll-margin-top: 5rem;
}
@media (prefers-reduced-motion: reduce) {
html { scroll-behavior: auto; }
}Porta prefix -webkit- però funciona a tots. Per a una sola línia, text-overflow: ellipsis.
.tres-lineas {
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 3;
overflow: hidden;
}Sense aquella última línia amb una paraula sola. pretty fa el mateix per a paràgrafs; on encara no arriba, simplement no fa res.
h1, h2, h3 {
text-wrap: balance;
}
p {
text-wrap: pretty;
}Amb color: transparent sense més, un navegador que no sàpiga retallar el fons deixaria el text invisible. Dins de @supports només s'aplica on funciona; a la resta es veu en lila llis.
.degradado {
color: #663399;
}
@supports (background-clip: text) or (-webkit-background-clip: text) {
.degradado {
background: linear-gradient(90deg, #663399, #e86f9b);
-webkit-background-clip: text;
background-clip: text;
color: transparent;
}
}El selector que vam demanar durant vint anys. Aquí el camp es marca en vermell quan el que escrius no és un correu.
.campo:has(input:user-invalid) {
border-color: crimson;
}
.campo:has(input:user-invalid) .error {
display: block;
}El d'una capa posterior guanya sempre, tingui l'especificitat que tingui. Adeu als !important per trepitjar un framework.
@layer reset, framework, mio;
@layer framework {
#app .boton { background: gray; }
}
@layer mio {
.boton { background: rebeccapurple; }
}El CSS ja nia sol. El & funciona com a Sass, i les media queries poden anar a dins.
.boton {
background: rebeccapurple;
color: white;
&:hover { background: color-mix(in oklch, rebeccapurple, black 20%); }
.icono { margin-inline-end: .4em; }
@media (width < 30rem) { width: 100%; }
}@starting-style dona el punt de partida d'una cosa que acaba d'aparèixer, i allow-discrete deixa animar display. Tot sense JS.
[popover] {
transition: opacity .25s, translate .25s,
display .25s allow-discrete, overlay .25s allow-discrete;
opacity: 0;
translate: 0 1rem;
}
[popover]:popover-open {
opacity: 1;
translate: 0 0;
@starting-style {
opacity: 0;
translate: 0 1rem;
}
}Una animació que avança amb l'scroll en lloc d'amb el temps. Sense IntersectionObserver. Fes scroll dins la demo.
@supports (animation-timeline: view()) {
@media (prefers-reduced-motion: no-preference) {
.aparece {
animation: aparece linear both;
animation-timeline: view();
animation-range: entry 0% cover 30%;
}
}
}
@keyframes aparece {
from { opacity: 0; scale: .8; }
}Hi ha gent a qui les animacions marejen de debò. Això les apaga gairebé del tot si ho han demanat al sistema.
@media (prefers-reduced-motion: reduce) {
*, *::before, *::after {
animation-duration: .01ms !important;
animation-iteration-count: 1 !important;
transition-duration: .01ms !important;
scroll-behavior: auto !important;
}
}Cada color diu les seves dues versions en una línia, i color-scheme fa que formularis i scrollbars l'acompanyin.
:root {
color-scheme: light dark;
--fondo: light-dark(#fbfaf7, #17121f);
--texto: light-dark(#221a2e, #ece6f5);
--acento: light-dark(rebeccapurple, #c9a7f2);
}
body {
background: var(--fondo);
color: var(--texto);
}Un sol color de marca i el hover, l'actiu i el fons suau en surten. Barrejar en oklch dona tons més nets.
.boton {
--c: rebeccapurple;
background: var(--c);
}
.boton:hover { background: color-mix(in oklch, var(--c), white 15%); }
.boton:active { background: color-mix(in oklch, var(--c), black 20%); }
.suave { background: color-mix(in oklch, var(--c) 12%, transparent); }Checkboxes, ràdios, sliders i barres de progrés natius, amb el teu color i sense refer-los.
:root {
accent-color: rebeccapurple;
}No treguis mai l'outline sense més. Amb :focus-visible l'anell surt en tabular i no en fer clic.
:focus-visible {
outline: 3px solid rebeccapurple;
outline-offset: 3px;
border-radius: 4px;
}Per al text d'un botó que només és una icona. display: none l'amagaria també per a qui no hi veu.
.solo-lectores {
position: absolute;
width: 1px;
height: 1px;
margin: -1px;
padding: 0;
overflow: hidden;
clip-path: inset(50%);
white-space: nowrap;
border: 0;
}