bei
--background-color--darkmode:
{{ background_color | transform_hex_to_dark_hsl }}
grid-template-columns:
repeat(auto-fit, minmax(min(100%, rem(352px)), 1fr));
max-width: calc(
12ch +
var(--audio-player-icon-size) +
var(--z-ds-space-xs) +
2 * var(--audio-player-padding-inline)
);
@supports (font-size: 1cqi) {
font-size: clamp(rem(82px), 8.2cqi, rem(164px));
}
Senior Frontend Developer
bei ZEIT Online
<div class="cp-area cp-area--lead">
<article class="zon-teaser zon-teaser--wide">
<figure class="zon-teaser__media zon-teaser__media--desktop-wide zon-teaser__media--mobile-square">...</figure>
<h3 class="zon-teaser__heading">
<span class="zon-teaser__title">...</span>
</h3>
</article>
</div>
.zon-teaser--wide {
display: flex;
gap: var(--z-ds-space-m);
margin-bottom: var(--z-ds-space-teaser);
@include respond-min($break-tablet-min) {
gap: var(--z-ds-space-l);
}
}
.zon-teaser--wide .zon-teaser__media {
max-width: $ds-content-width;
}
body {
background: white;
color: black;
}
@media (prefers-color-scheme: dark) {
.body {
background: black;
color: white;
}
}
:root {
--z-ds-color-text-100: #252525; // Primary Information
--z-ds-color-text-70: #444; // Secondary Information
--z-ds-color-text-40: #999; // Low Prio
--z-ds-color-background-0: #fff; // Primary
}
:root {
@media (prefers-color-scheme: dark) {
--z-ds-color-text-100: #fff;
--z-ds-color-text-70: #bababa;
--z-ds-color-text-40: #8b8b8b;
--z-ds-color-background-0: #121212;
}
}
body {
background: var(--z-ds-color-background-0);
color: var(--z-ds-color-text-100);
}
--z-ds-space-xxs: #{remify(4px)};
--z-ds-space-xs: #{remify(8px)};
--z-ds-space-s: #{remify(12px)};
--z-ds-space-m: #{remify(16px)};
--z-ds-space-l: #{remify(20px)};
--z-ds-space-xl: #{remify(24px)};
--z-ds-space-xxl: #{remify(32px)};
--z-ds-space-gap: #{remify(20px)};
--z-ds-space-teaser: #{remify(24px)};
@include respond-min($break-tablet-min) {
--z-ds-space-xxs: #{remify(6px)};
--z-ds-space-xxl: #{remify(54px)};
--z-ds-space-gap: #{remify(32px)};
--z-ds-space-teaser: #{remify(54px)};
}
--z-ds-fontsize-s: #{remify(20px)};
--z-ds-fontsize-m: #{remify(20px)};
--z-ds-fontsize-l: #{remify(22px)};
@include respond-min($break-tablet-min) {
--z-ds-fontsize-m: #{remify(22px)};
--z-ds-fontsize-l: #{remify(24px)};
}
.zon-teaser h2 {
font-size: var(--z-ds-fontsize-m);
}
.zon-teaser--large h2 {
font-size: var(--z-ds-fontsize-l);
}
.audio-player {
--audio-player-color-background: var(--z-ds-color-background-10);
--audio-player-color-text: var(--z-ds-color-text-70);
--audio-player-icon-size: #{rem(14px)};
--audio-player-padding-block: #{rem(8px)};
--audio-player-padding-inline: var(--z-ds-space-s);
background-color: var(--audio-player-color-background);
/* Need static width for animation.
Is calculated with character count, icon width, flexbox gap plus padding
text + icon width + flexbox gap + padding-left + padding-right */
/* stylelint-disable order/properties-alphabetical-order */
// prettier-ignore
max-width: calc(
12ch + var(--audio-player-icon-size) + var(--z-ds-space-xs) + 2 * var(--audio-player-padding-inline)
);
/* stylelint-enable */
}
.audio-player--large {
--audio-player-color-background: var(--z-ds-color-text-100);
--audio-player-color-text: var(--z-ds-color-background-20);
--audio-player-icon-size: #{rem(18px)};
--audio-player-padding-block: #{rem(12px)};
--audio-player-padding-inline: var(--z-ds-space-m);
}
.audio-player__icon--replay {
--audio-player-icon-size: #{rem(18px)};
}
/* JS */
this.indicator.style.setProperty(
'--number-of-dots', this.dotsVisible);
/* CSS */
.gallery__indicator {
width: calc((var(--number-of-dots) + 1) * 1ch);
}
this.header.style.setProperty(
'--nav-topic-height', `${topicHeight}px`);
activeSlide.style.setProperty(
'--progress', `${oldProgress + 1}%`);
<section
class="area--colored area--is-dark"
style="--background-color: #293443;
--background-color--darkmode: hsl(215, 24%, 21%)">
CSS
.area--colored {
background-color: var(--background-color, '#fff8e7');
@include dark-mode {
background-color: var(--background-color--darkmode);
}
}
<section
class="area--colored area--is-dark"
style="--background-color: #293443;
--background-color--darkmode: hsl(215, 24%, 21%)">
Jinja (Template)
<section class="area--colored
area--is-{{ background_color | get_luminance_modifier) }}"
style="--background-color: {{ background_color }};
--background-color--darkmode:
{{ background_color | transform_hex_to_dark_hsl }}">
@zeit.web.register_test
def valid_hex(hex):
if not hex:
return None
hex = hex.lstrip('#')
match = re.search(r'^(?:[0-9a-fA-F]{6})$', hex)
if match:
return True
return False
@zeit.web.register_filter
def color_is_dark(hexcolor):
if not hexcolor:
return None
# takes a hex background color (no shorthands) and computes
# if the color is dark in accessibility context
# i.e. a light color needs to be used for contrast
# like in light font on dark background
threshold = 0.5
try:
# we must manually filter out the hex sign, if color should contain it
hexcolor = hexcolor[1:] if hexcolor[0] == '#' else hexcolor
red, green, blue = tuple(int(hexcolor[i:i + 2], 16) for i in (0, 2, 4))
# perceived lightness by W3C working draft
# https://www.w3.org/TR/AERT/#color-contrast
luminance = (red * 0.299 + green * 0.587 + blue * 0.114) / 255
return luminance < threshold
except Exception:
return None
@zeit.web.register_filter
def get_luminance_modifier(hexcolor):
return 'dark' if color_is_dark(hexcolor) else 'light'
@zeit.web.register_filter
def transform_hex_to_dark_hsl(hexcolor):
hue, saturation, luminance = zeit.web.core.utils.hex_to_hsl(hexcolor)
if not color_is_dark(hexcolor):
saturation = saturation - 20 if saturation >= 20 else 0
luminance = 30
return f'hsl({hue}, {saturation}%, {luminance}%)'
@zeit.web.register_filter
def transform_hex_to_rgb(hexcolor):
if not valid_hex(hexcolor):
return None
return ', '.join(map(str, zeit.web.core.utils.hex_to_rgb(hexcolor)))
@zeit.web.register_filter
def transform_hex_to_rgba(hexcolor, alpha=1):
if not valid_hex(hexcolor):
return None
red, green, blue = zeit.web.core.utils.hex_to_rgb(hexcolor)
return f'rgba({red}, {green}, {blue}, {alpha})'
Viel Python Logik -> einfaches CSS *
--z-ds-color-general-black-60: rgba(0, 0, 0, 0.6);
--z-ds-color-general-white-60: rgba(255, 255, 255, 0.6);
mix-blend-mode: multiply;
*,
**
.article__item {
margin: 30px 20px;
@include respond-min($break-tablet-min) {
margin: 30px auto;
}
@include respond-min($break-desktop-min) {
margin: 60px auto;
}
}
.article__item {
margin: 30px 20px;
@include respond-min($break-tablet-min) {
margin-left auto;
margin-right: auto;
}
@include respond-min($break-desktop-min) {
margin-top: 60px;
margin-bottom: 60px;
}
}
--margin-vertical: 30px;
--margin-horizontal: 20px;
@include respond-min($break-tablet-min) {
--margin-horizontal: auto;
}
@include respond-min($break-desktop-min) {
--margin-vertical: 60px;
}
.article__item {
margin: var(--margin-vertical) var(--margin-horizontal);
}
.article__item {
margin: 30px 20px;
@include respond-min($break-tablet-min) {
margin-left auto;
margin-right: auto;
}
@include respond-min($break-desktop-min) {
margin-top: 60px;
margin-bottom: 60px;
}
}
.article__item {
margin: 30px 20px;
@include respond-min($break-tablet-min) {
/* margin-left auto; */
/* margin-right: auto; */
margin-inline: auto;
}
@include respond-min($break-desktop-min) {
/* margin-top: 60px; */
/* margin-bottom: 60px; */
margin-block: 60px;
}
}
.article__item {
margin: 30px 20px;
@include respond-min($break-tablet-min) {
margin-inline: auto;
}
@include respond-min($break-desktop-min) {
margin-block: 60px;
}
}
.u-apart {
margin-block: var(--z-ds-space-xxl);
}
.image-container {
height: 0;
overflow: hidden;
padding-bottom: 56.25%;
position: relative;
img {
height: 100%;
left: 0;
position: absolute;
top: 0;
width: 100%;
}
}
img {
aspect-ratio: 16/9
}
margin-inline: calc(-1 * var(--z-ds-space-xxl));
/* Need static width for animation.
Is calculated with character count, icon width, flexbox gap plus padding
text + icon width + flexbox gap + padding-left + padding-right */
/* prettier-ignore */
max-width: calc(
12ch + var(--audio-player-icon-size) + var(--z-ds-space-xs) + 2 * var(--audio-player-padding-inline)
);
.teaser-liveblog__text {
line-height: 1.5;
max-height: calc(1.5 * 3em);
overflow: hidden;
}
.teaser-liveblog__text {
-webkit-box-orient: vertical;
-webkit-line-clamp: 3;
display: -webkit-box;
overflow: hidden;
}
.header-fullwidth__media-container {
height: 60vh;
}
.split-header > * {
width: 50vw;
}
für Größenangaben
Demo Time: codepen.io
@supports (container-type: inline-size) {
@container audio-actions (width < 520px) {
.audio-player[data-state="playing"] {
~ *:not(.bookmark) {
display: none;
}
}
}
}
// extra space after last standard teaser
.cp-region:has(.cp-area--standard:last-child > .zon-teaser--standard:last-child) {
margin-bottom: var(--z-ds-space-xxl);
.cp-region:has(.cp-area[hidden]:only-child) {
margin-block: 0;
// edge case for long title with wrapped topic links and no subtitle
&:not(:has(.headed-meta__kicker)) {
row-gap: var(--z-ds-space-l);
<div class="zon-teaser-actions">
<button class="z-text-button">Podcast abonnieren</button>
</div>
.z-text-button {
color: black;
&:hover {
color: red;
}
}
.zon-teaser__actions .z-text-button {
color: inherit;
}
// keep specificity low to preserve hover state color
.zon-teaser__actions :where(.z-text-button) {
color: inherit;
}