Grave dybere ned i containerstilforespørgsler

Kildeknude: 1765194

Jeg skrev nogle tidlige tanker om forespørgsler i containerstil et stykke tid tilbage. Det er stadig tidlige dage. De er allerede defineret i CSS Containment Module Level 1 specifikation (i øjeblikket i Redaktørudkast-status), men der er stadig et par udestående diskussioner, der finder sted.

Den grundlæggende idé er, at vi kan definere en beholder og derefter anvende stilarter betinget på dens efterkommere baseret på dens beregnede stil.

@container ?  {
  /* conditional styles */
}

Det bedste eksempel, jeg har set indtil videre, er at fjerne kursiv fra noget lignende , og når de bruges i en kontekst, hvor indholdet allerede er kursiv:

em, i, q {
  font-style: italic; /* default UA behavior */
}

/* When the container's font-style is italic, remove italics from these elements. */
@container style(font-style: italic) {
  em, i, q {
    font-style: normal;
  }
}

Det er den generelle idé. Men hvis du ikke vidste det, holder Miriam Suzanne, som er redaktør af specifikationen, et løbende og grundigt sæt af personlige noter om forespørgsler i containerstil der er offentligt tilgængeligt. Den blev opdateret den anden dag, og jeg brugte noget tid derinde på at prøve at pakke mit hoved om mere nuancerede aspekter af stilforespørgsler. Det er uofficielle ting, men jeg tænkte, at jeg ville notere nogle ting ned, som skilte sig ud for mig. Hvem ved? Måske er det ting, vi efterhånden kan se frem til!

Hvert element er en stilbeholder

Vi behøver ikke engang udtrykkeligt at tildele en container-name or container-type at definere en stilbeholder, fordi alt er en stilbeholder som standard.

Så du ser det eksempel ovenfor, der fjerner kursiv? Bemærk, at det ikke identificerer en beholder. Den hopper lige til forespørgslen ved hjælp af style() fungere. Så hvilken beholder bliver der spurgt til? Det bliver den direkte forælder til elementerne modtage de anvendte stilarter. Og hvis ikke det, så er det det den næste nærmeste relative beholder der har forrang.

Det kan jeg lide. Det er meget CSS-agtigt for forespørgslen at søge efter et match og derefter fortsætte med at boble op, indtil den finder en matchende betingelse.

Det var svært for min lille hjerne at forstå, hvorfor vi kan slippe af sted med en implicit beholder baseret på stilarter, men ikke så meget, når vi har at gøre med dimensionelle forespørgsler, som f.eks. size , inline-size. Miriam forklarer det fint:

Dimensionsforespørgsler kræver css inddæmning på containerens størrelse, layout og stil for at forhindre layoutløkker. Indeslutning er en invasiv ting at anvende bredt, så det var vigtigt, at forfattere havde omhyggelig kontrol over, hvilke elementer der er (eller ikke er) størrelse beholdere.

Stilbaserede forespørgsler har ikke den samme begrænsning. Der er allerede ingen måde i CSS for efterkommerstile at have indflydelse på en forfaders beregnede stilarter. Så ingen indeslutning er påkrævet, og der er ingen invasive eller uventede bivirkninger ved at etablere et element som en stilforespørgselsbeholder.

(Fremhæv min)

Det hele kommer ned til konsekvenser - som der ikke er nogen af, så vidt alt er en stilforespørgselsbeholder lige ud af boksen.

  • Hvis en container er fundet: betingelser er løst mod denne container.
  • Hvis flere containere matcher: den nærmeste relative container har forrang.
  • Hvis der ikke findes noget match: unknown vendt tilbage.

Det er det samme "tilgivende" ånd som resten af ​​CSS.

En container kan understøtte både dimensions- og stilforespørgsler

Lad os sige, at vi vil definere en stilforespørgsel uden en eksplicit container-name:

@container style(font-style: italic) {
  em {
    font-style: normal;
  }
}

Dette fungerer fordi alle elementer er stilbeholdereuanset container-type. Det er det, der giver os mulighed for implicit at forespørge efter stilarter og stole på det nærmeste match. Og det er helt fint, da der igen ikke er nogen negative bivirkninger ved etablering af stilbeholdere.

Vi skal bruge en eksplicit container-type for dimensionelle forespørgsler, men ikke så meget for stilforespørgsler, da hvert element er en stilforespørgsel. Det betyder også, at denne beholder både er en stilart , dimensionelle forespørgsel:

.card-container {
  container: card / inline-size; /* implictly a style query container as well */
}

Ekskludering af en beholder fra at blive forespurgt

Måske vil vi ikke have en container til at deltage i matchningsprocessen. Det er der, det måske er muligt at indstille container-type: none på et element.

.some-element {
  container-type: none;
}

Eksplicitte stilforespørgselscontainere giver mere kontrol over, hvad der bliver forespurgt

Hvis vi f.eks. skulle skrive en stilforespørgsel til padding , er der ingen pålidelig måde at bestemme den bedst matchende container, uanset om vi arbejder med en eksplicit navngivet container eller den nærmeste direkte overordnede. Det er fordi padding er ikke en arvelig ejendom.

Så i disse tilfælde burde vi bruge container-name for eksplicit at informere browseren om, hvilke containere de kan trække fra. Vi kan endda give en container flere eksplicitte navne for at få den til at matche flere betingelser:

.card {
  container-name: card layout theme;
}

Åh, og container-name accepterer et hvilket som helst antal valgfrie og genanvendelige navne på en container! Det er endnu mere fleksibilitet, når det kommer til at hjælpe browseren med at træffe et valg, når de søger efter matches.

.theme {
  container-name: theme;
}
.grid {
  container-name: layout;
}
.card {
  container-name: card layout theme;
}

Jeg spekulerer lidt på, om det også kan betragtes som en "tilbagegang" i tilfælde af, at en container bliver forbigået.

Stilforespørgsler kan kombineres

or , and operatører giver os mulighed for at kombinere wueries for at holde tingene TØRRE:

@container bubble style(--arrow-position: start start) or style(--arrow-position: end start) {
  .bubble::after {
    border-block-end-color: inherit;
    inset-block-end: 100%;
  }
}

/* is the same as... */
@container bubble style(--arrow-position: start start) {
  /* etc. */
}
@container bubble style(--arrow-position: end start) {
  /* etc. */
}

Skiftende stilarter

Der er et lille overlap mellem containerstilforespørgsler og der arbejdes på at definere en toggle() funktion. For eksempel kan vi cykle gennem to font-style værdier, siger italic , normal:

em, i, q {
  font-style: italic;
}

@container style(font-style: italic) {
  em, i, q {
    font-style: normal;
  }
}

Fedt nok. Men forslaget til CSS Toggles antyder, at toggle() funktion ville være en enklere tilgang:

em, i, q {
  font-style: toggle(italic, normal);
}

Men alt ud over denne form for binær brug er hvor toggle() er mindre egnet. Stilforespørgsler er dog gode at gå. Miriam identificerer tre tilfælde, hvor stilforespørgsler er mere egnede end en toggle():

/* When font-style is italic, apply background color. */
/* Toggles can only handle one property at a time. */
@container style(font-style: italic) {
  em, i, q {
    background: lightpink;
  }
}

/* When font-style is italic and --color-mode equals light */
/* Toggles can only evaluate one condition at a time */
@container style((font-style: italic) and (--color-mode: light)) {
  em, i, q {
    background: lightpink;
  }
}

/* Apply the same query condition to multiple properties */
/* Toggles have to set each one individually as separate toggles */
@container style(font-style: italic) {
  em, i, q {
    /* clipped gradient text */
    background: var(--feature-gradient);
    background-clip: text;
    box-decoration-break: clone;
    color: transparent;
    text-shadow: none;
  }
}

Stilforespørgsler løser "Custom Property Toggle Hack"

Bemærk, at stilforespørgsler er en formel løsning til "CSS tilpasset egenskab skifte trick". Derinde sætter vi en tom brugerdefineret egenskab (--foo: ;) og brug den kommaseparerede fallback-metode til at "slå" egenskaber til og fra, når den tilpassede egenskab derefter er indstillet til en reel værdi.

button {
  --is-raised: ; /* off by default */
  
  border: 1px solid var(--is-raised, rgb(0 0 0 / 0.1));
  box-shadow: var(
    --is-raised,
    0 1px hsl(0 0% 100% / 0.8) inset,
    0 0.1em 0.1em -0.1em rgb(0 0 0 / 0.2)
  );
  text-shadow: var(--is-raised, 0 -1px 1px rgb(0 0 0 / 0.3));
}

button:active {
  box-shadow: var(--is-raised, 0 1px 0.2em black inset);
}

#foo {
  --is-raised: initial; /* turned on, all fallbacks take effect. */
}

Det er super fedt, også meget arbejde, som stilbeholderforespørgsler gør trivielt.

Stilforespørgsler og CSS-genereret indhold

For genereret indhold produceret af content ejendom af ::before , ::after pseudo-elementer, er den matchende container det element, som indholdet genereres på.

.bubble {
  --arrow-position: end end;
  container: bubble;
  border: medium solid green;
  position: relative;
}

.bubble::after {
  content: "";
  border: 1em solid transparent;
  position: absolute;
}

@container bubble style(--arrow-position: end end) {
  .bubble::after {
    border-block-start-color: inherit;
    inset-block-start: 100%;
    inset-inline-end: 1em;
  }
}

Stilforespørgsler og webkomponenter

Vi kan definere en webkomponent som en container og forespørge efter stil. For det første har vi af komponenten:


  
… …

Så bruger vi :host pseudo-element som en beholder til at sætte en container-name, en container-type, og nogle attributter på højt niveau på det:

:host {
  container: media-host / inline-size;
  --media-location: before;
  --media-style: square;
  --theme: light;
}

Elementer inde i kan forespørge om parametrene for element:

@container media-host style(--media-style: round) {
  [part='img'] {
    border-radius: 100%;
  }
}

Hvad er det næste?

Igen, alle de ting, jeg har noteret ned her, er baseret på Miriams noter, og disse noter er ikke en erstatning for den officielle spec. Men de er en indikation af, hvad der diskuteres, og hvor tingene kan lande i fremtiden. Jeg sætter pris på, at Miriam sammenkædede en håndfuld udestående diskussioner, der stadig finder sted, som vi kan følge for at holde styr på tingene:

Tidsstempel:

Mere fra CSS-tricks