Das CSS :has()
Pseudo-Klasse wird in vielen Browsern mit eingeführt Chrome und Safari unterstützt sie bereits voll und ganz. Es wird oft als „übergeordneter Selektor“ bezeichnet – wie in, wir können ein übergeordnetes Element aus einem untergeordneten Selektor auswählen – aber es gibt noch so viel mehr :has()
kann uns bei der Lösung helfen. Eines dieser Dinge ist die Neuerfindung des anklickbaren Kartenmusters, das viele von uns von Zeit zu Zeit gerne verwenden.
Wir schauen uns an, wie :has()
kann uns beim Umgang mit verknüpften Karten helfen, aber zuerst …
:has()
Pseudoklasse?
Was ist das Es gibt schon eine Bündel of groß Beiträge herumschwimmen die sehr gut erklären, was :has()
ist und wofür es verwendet wird, aber es ist immer noch so neu, dass wir hier auch ein paar Worte darüber verlieren sollten.
:has()
ist eine relationale Pseudoklasse, die Teil von ist W3C Selectors Level 4 Arbeitsentwurf. Darum geht es bei den Klammern: übereinstimmende Elemente, die sich auf bestimmte untergeordnete Elemente beziehen oder, genauer gesagt, enthalten.
/* Matches an article element that contains an image element */
article:has(img) { }
/* Matches an article element with an image contained immediately within it */
article:has(> img) { }
Sie können also sehen, warum wir es vielleicht einen „Eltern“-Selektor nennen möchten. Aber wir können es auch mit anderen funktionalen Pseudoklassen kombinieren, um spezifischer zu werden. Angenommen, wir möchten Artikel gestalten, die dies tun nicht irgendwelche Bilder enthalten. Wir können die Beziehungskräfte von kombinieren :has()
mit den Verneinungskräften von :not()
das zu tun:
/* Matches an article without images */
article:not(:has(img)) { }
Aber das ist nur der Anfang, wie wir Kräfte bündeln können, um mehr zu erreichen :has()
. Bevor wir uns speziell der Lösung des Rätsels um anklickbare Karten zuwenden, wollen wir uns ein paar Möglichkeiten ansehen, wie wir sie derzeit angehen, ohne sie zu verwenden :has()
.
Wie wir derzeit mit anklickbaren Karten umgehen
Es gibt drei Hauptansätze, wie Menschen heutzutage eine vollständig anklickbare Karte erstellen, und um die Leistungsfähigkeit dieser Pseudoklasse vollständig zu verstehen, ist es schön, eine kleine Zusammenfassung zu haben.
Der „Link as a Wrapper“-Ansatz
Dieser Ansatz wird recht häufig verwendet. Ich verwende diesen Ansatz nie, aber ich habe eine kurze Demo erstellt, um ihn zu demonstrieren:
Hier gibt es viele Bedenken, insbesondere wenn es um Barrierefreiheit geht. Wenn Benutzer mit Ihrer Website navigieren die Rotorfunktion, sie werden den vollständigen Text darin hören element — die Überschrift, der Text und der Link. Jemand möchte das vielleicht nicht durchstehen. Wir können es besser. Seit HTML5 können wir Blockelemente innerhalb von verschachteln
Element. Aber es fühlt sich für mich nie richtig an, besonders aus diesem Grund.
Vorteile:
- Schnell umzusetzen
- Semantisch korrekt
Nachteile:
- Bedenken hinsichtlich der Zugänglichkeit
- Text nicht wählbar
- Viel Aufwand beim Überschreiben von Stilen, die Sie für Ihre Standardlinks verwendet haben
Die JavaScript-Methode
Mit JavaScript können wir einen Link zu unserer Karte hinzufügen, anstatt ihn in das Markup zu schreiben. Ich habe diese großartige CodePen-Demo von gefunden Kostenentwicklung der dabei auch den Kartentext auswählbar gemacht hat:
Dieser Ansatz hat viele Vorteile. Unsere Links sind fokussiert zugänglich und wir können sogar Text auswählen. Aber es gibt einige Nachteile, wenn es ums Styling geht. Wenn wir diese Karten zum Beispiel animieren wollen, müssten wir hinzufügen :hover
Stile auf unserer Haupt .card
Wrapper anstelle des Links selbst. Wir würden auch nicht von den Animationen profitieren, wenn die Links durch Tastaturtabbing im Fokus sind.
Vorteile:
- Kann perfekt zugänglich gemacht werden
- Fähigkeit, Text auszuwählen
Nachteile:
- Erfordert JavaScript
- Rechtsklick nicht möglich (könnte aber mit zusätzlichem Scripting behoben werden)
- Erfordert viel Styling auf der Karte selbst, was beim Fokussieren des Links nicht funktionieren würde
::after
Selektor-Ansatz
Das Bei dieser Methode müssen wir die Karte mit relativer Positionierung einstellen und dann die absolute Positionierung auf den Links einstellen ::after
Pseudoselektor eines Links. Dies erfordert kein JavaScript und ist ziemlich einfach zu implementieren:
Hier gibt es ein paar Abstriche, vor allem bei der Textauswahl. Wenn Sie keinen höheren Z-Index auf Ihrem Kartenkörper angeben, können Sie keinen Text auswählen, aber wenn Sie dies tun, seien Sie gewarnt, dass das Klicken auf den Text Ihren Link nicht aktiviert. Ob Sie wählbaren Text wünschen oder nicht, bleibt Ihnen überlassen. Ich denke, es kann ein UX-Problem sein, aber es hängt vom Anwendungsfall ab. Der Text ist immer noch für Screenreader zugänglich, aber mein Hauptproblem mit der Methode sind die fehlenden Animationsmöglichkeiten.
Vorteile:
- Einfach zu implementieren
- Zugänglicher Link ohne aufgeblähten Text
- Funktioniert beim Schweben und Fokussieren
Nachteile:
- Text ist nicht wählbar
- Sie können den Link nur animieren, da dies das Element ist, über das Sie schweben.
::after
mit :has()
Ein neuer Ansatz: Using Nachdem wir nun die bestehenden Ansätze für anklickbare Karten etabliert haben, möchte ich die Einführung zeigen :has()
to the mix behebt die meisten dieser Mängel.
Lassen Sie uns diesen Ansatz auf den letzten Ansatz stützen, den wir uns angesehen haben ::after
auf dem Link-Element. Wir können tatsächlich verwenden :has()
um die Animationseinschränkungen dieses Ansatzes zu überwinden.
Beginnen wir mit dem Markup:
Some Heading
Curabitur convallis ac quam vitae laoreet. Nulla mauris ante, euismod sed lacus sit amet, congue bibendum eros. Etiam mattis lobortis porta. Vestibulum ultrices iaculis enim imperdiet egestas.
Ich werde die Dinge so einfach wie möglich halten, indem ich auf Elemente im CSS statt auf Klassen abziele.
Für diese Demo fügen wir der Karte beim Hover einen Bildzoom und einen Schatten hinzu und animieren den Link mit einem Pfeil, der auftaucht, und ändern gleichzeitig die Textfarbe des Links. Um dies zu vereinfachen, fügen wir einige benutzerdefinierte Eigenschaften hinzu, die auf unserer Karte liegen. Hier ist das grundlegende Styling:
/* The card element */
article {
--img-scale: 1.001;
--title-color: black;
--link-icon-translate: -20px;
--link-icon-opacity: 0;
position: relative;
border-radius: 16px;
box-shadow: none;
background: #fff;
transform-origin: center;
transition: all 0.4s ease-in-out;
overflow: hidden;
}
/* The link's ::after pseudo */
article a::after {
content: "";
position: absolute;
inset-block: 0;
inset-inline: 0;
cursor: pointer;
}
Groß! Wir haben eine Anfangsskalierung für das Bild hinzugefügt (--img-scale: 1.001
), die Anfangsfarbe der Kartenüberschrift (--title-color: black
) und einige zusätzliche Eigenschaften, die wir verwenden werden, damit unser Pfeil aus dem Link herausspringt. Wir haben auch einen leeren Zustand von gesetzt box-shadow
Deklaration , um sie später zu animieren . Dies richtet das ein, was wir jetzt für die anklickbare Karte benötigen. Fügen wir also einige Zurücksetzungen und Stile hinzu, indem wir diese benutzerdefinierten Eigenschaften zu den Elementen hinzufügen, die wir animieren möchten:
article h2 {
margin: 0 0 18px 0;
font-family: "Bebas Neue", cursive;
font-size: 1.9rem;
letter-spacing: 0.06em;
color: var(--title-color);
transition: color 0.3s ease-out;
}
article figure {
margin: 0;
padding: 0;
aspect-ratio: 16 / 9;
overflow: hidden;
}
article img {
max-width: 100%;
transform-origin: center;
transform: scale(var(--img-scale));
transition: transform 0.4s ease-in-out;
}
article a {
display: inline-flex;
align-items: center;
text-decoration: none;
color: #28666e;
}
article a:focus {
outline: 1px dotted #28666e;
}
article a .icon {
min-width: 24px;
width: 24px;
height: 24px;
margin-left: 5px;
transform: translateX(var(--link-icon-translate));
opacity: var(--link-icon-opacity);
transition: all 0.3s;
}
.article-body {
padding: 24px;
}
Seien wir freundlich zu den Menschen und fügen Sie auch ein hinzu Screenreader-Klasse hinter dem Link versteckt:
.sr-only:not(:focus):not(:active) {
clip: rect(0 0 0 0);
clip-path: inset(50%);
height: 1px;
overflow: hidden;
position: absolute;
white-space: nowrap;
width: 1px;
}
Unsere Karte fängt an, ziemlich süß auszusehen. Es ist Zeit, ein bisschen Magie hinzuzufügen. Mit dem :has()
Pseudo-Klasse können wir jetzt prüfen, ob unser Link schwebt oder fokussiert ist, dann unsere benutzerdefinierten Eigenschaften aktualisieren und eine hinzufügen box-shadow
. Mit diesem kleinen Stück CSS erwacht unsere Karte wirklich zum Leben:
/* Matches an article element that contains a hover or focus state */
article:has(:hover, :focus) {
--img-scale: 1.1;
--title-color: #28666e;
--link-icon-translate: 0;
--link-icon-opacity: 1;
box-shadow: rgba(0, 0, 0, 0.16) 0px 10px 36px 0px, rgba(0, 0, 0, 0.06) 0px 0px 0px 1px;
}
Sehen Sie, was da oben ist? Jetzt erhalten wir die aktualisierten Stile, wenn jedem Das untergeordnete Element in der Karte wird bewegt oder fokussiert. Und obwohl das Link-Element das einzige ist, das einen Schwebe- oder Fokuszustand in der enthalten kann ::after
klickbarer Kartenansatz, können wir diesen verwenden, um das übergeordnete Element abzugleichen und die Übergänge anzuwenden.
Und da haben Sie es. Nur ein weiterer leistungsstarker Anwendungsfall für die :has()
Wähler. Wir können nicht nur ein übergeordnetes Element abgleichen, indem wir andere Elemente als Argumente deklarieren, sondern wir können auch Pseudos verwenden, um Eltern abzugleichen und zu formatieren.
Vorteile:
- Für alle
- Animierbar
- Kein JavaScript erforderlich
- Verwendung
:hover
auf das richtige Element
Nachteile:
- Text ist nicht einfach auswählbar.
- Die Browserunterstützung ist auf Chrome und Safari beschränkt (wird in Firefox hinter einem Flag unterstützt).
Hier ist eine Demo mit dieser Technik. Sie bemerken vielleicht eine zusätzliche Verpackung um die Karte, aber damit spiele ich nur herum Containerabfragen, was nur eines dieser anderen fantastischen Dinge ist, die in allen gängigen Browsern eingeführt werden.
Ich habe welche andere Beispiele Sie möchten teilen? Andere Lösungen oder Ideen sind im Kommentarbereich mehr als willkommen.