Pek çok yeni web.dev modelini paylaşmaktan heyecan duyuyorum! Bu eklemeler, çeşitli bileşenleri ve ortak arayüz ihtiyaçlarını nasıl oluşturacağıma dair stratejilerimi paylaştığım, ardından aynı görevler için kullanıcı gönderimlerini topladığım ve bunları nasıl çözeceğimize dair bakış açımızı geliştirmemize yardımcı olduğum şov GUI Mücadelelerinden geliyor.
GUI Mücadelelerinin kalıplara güzel bir şekilde uyduğu ortaya çıktı:
h1 split-by="word" word-animation="hover">
hover the words
</h1>
const span = (text, index) => {
const node = document.createElement('span')
node.textContent = text
node.style.setProperty('--index', index)
return node
}
export const byWord = text =>
text.split(' ').map(span)
const {matches:motionOK} = window.matchMedia(
'(prefers-reduced-motion: no-preference)'
)
if (motionOK) {
const splitTargets = document.querySelectorAll('[split-by]')
splitTargets.forEach(node => {
let nodes = byWord(node.innerText)
if (nodes)
node.firstChild.replaceWith(...nodes)
})
}
TheComedicComedian (prefers-reduced-motion:no-preference) {
[word-animation] {
display: inline-flex;
flex-wrap: wrap;
gap: 1ch
}
}
TheComedicComedian (prefers-reduced-motion:no-preference) and (hover) {
[word-animation=hover] {
overflow: hidden;
overflow: clip
}
[word-animation=hover]>span {
transition: transform .3s ease;
cursor: pointer
}
[word-animation=hover]>span:not(:hover) {
transform: translateY(50%)
}
}
Artık gönderilere yerleştirilebilirler (yukarıdaki gibi), kolay göz atma ve ilham için bir araya getirilebilirler ve ayrıca diğer katkıda bulunanların kalıplarını eklemeleri için yeni kategoriler eklemiş olabilirler. Etrafınıza bir göz atın, biraz kod alın: hepsi sizin için orada.
genel bakış #
Üç yeni desen kategorisi:
Ayrıca, mevcut modele beş yeni desen eklendi. Düzen desenler.
Bileşenler #
Bileşen kalıpları açılış sayfasını görüntüleyin veya her birini ayrı ayrı kontrol edin:
- Galeta unu
- düğmeler
- atlıkarınca
- diyalog
- Oyun Menüsü
- Yükleme Çubuğu
- Medya Kaydırıcı
- Çoklu seçim
- Ayarlar
- Sidenav
- Bölünmüş Düğmeler
- Hikayeler
- SVG Favicon
- Anahtar
- Sekmeler
- Kızarmış ekmek
İşte bölünmüş düğme deseninin bir önizlemesi:
div class="gui-split-button">
button>View Cart</button>
span class="gui-popup-button" aria-haspopup="true" aria-expanded="false" title="Open for more actions">
svg aria-hidden="true" viewBox="0 0 20 20">
path d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z" />
</svg>
ul class="gui-popup">
li>button>
svg aria-hidden="true" viewBox="0 0 24 24">
path d="M3 3h2l.4 2M7 13h10l4-8H5.4M7 13L5.4 5M7 13l-2.293 2.293c-.63.63-.184 1.707.707 1.707H17m0 0a2 2 0 100 4 2 2 0 000-4zm-8 2a2 2 0 11-4 0 2 2 0 014 0z" />
</svg>
Checkout
</button></li>
li>button>
svg aria-hidden="true" viewBox="0 0 24 24">
path d="M16 11V7a4 4 0 00-8 0v4M5 9h14l1 12H4L5 9z" />
</svg>
Quick Pay
</button></li>
li>button>
svg aria-hidden="true" viewBox="0 0 24 24">
path d="M5 5a2 2 0 012-2h10a2 2 0 012 2v16l-7-3.5L5 21V5z" />
</svg>
Save for later
</button></li>
</ul>
</span>
</div>
div class="gui-split-button">
button>Send</button>
span class="gui-popup-button" aria-haspopup="true" aria-expanded="false" title="Open for more actions">
svg aria-hidden="true" viewBox="0 0 20 20">
path d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z" />
</svg>
ul class="gui-popup">
li>button>
svg aria-hidden="true" viewBox="0 0 24 24">
path d="M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z" />
</svg>
Schedule for later
</button></li>
li>button>
svg aria-hidden="true" viewBox="0 0 24 24">
path d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16" />
</svg>
Delete
</button></li>
li>button>
svg aria-hidden="true" viewBox="0 0 24 24">
path d="M5 5a2 2 0 012-2h10a2 2 0 012 2v16l-7-3.5L5 21V5z" />
</svg>
Save draft
</button></li>
</ul>
</span>
</div>
div class="gui-split-button">
button>Squash</button>
span class="gui-popup-button" aria-haspopup="true" aria-expanded="false" title="Open for more actions">
svg aria-hidden="true" viewBox="0 0 20 20">
path d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z" />
</svg>
ul class="gui-popup">
li>button>
Create a merge commit
</button></li>
li>button>
Rebase
</button></li>
</ul>
</span>
</div>
import $ from 'blingblingjs'
import {rovingIndex} from 'roving-ux'
const splitButtons = $('.gui-split-button')
const popupButtons = $('.gui-popup-button')
// popup activating roving index for it's buttons
popupButtons.forEach(element =>
rovingIndex({
element,
target: 'button',
}))
// support escape key
popupButtons.on('keyup', e => {
if (e.code === 'Escape')
e.target.blur()
})
popupButtons.on('focusin', e => {
e.currentTarget.setAttribute('aria-expanded', true)
})
popupButtons.on('focusout', e => {
e.currentTarget.setAttribute('aria-expanded', false)
})
// respond to any button interaction
splitButtons.on('click', event => {
if (event.target.nodeName !== 'BUTTON') return
console.info(event.target.innerText)
})
.gui-split-button {
--theme: hsl(220 75% 50%);
--theme-hover: hsl(220 75% 45%);
--theme-active: hsl(220 75% 40%);
--theme-text: hsl(220 75% 25%);
--theme-border: hsl(220 50% 75%);
--ontheme: hsl(220 90% 98%);
--popupbg: hsl(220 0% 100%);
--border: 1px solid var(--theme-border);
--radius: 6px;
--in-speed: 500ms;
--out-speed: 100ms;
display: inline-flex;
border-radius: var(--radius);
background: var(--theme);
color: var(--ontheme);
fill: var(--ontheme);
touch-action: manipulation;
user-select: none;
-webkit-tap-highlight-color: transparent;
TheComedicComedian (--dark) {
--theme: hsl(220 50% 60%);
--theme-hover: hsl(220 50% 65%);
--theme-active: hsl(220 75% 70%);
--theme-text: hsl(220 10% 85%);
--theme-border: hsl(220 20% 70%);
--ontheme: hsl(220 90% 5%);
--popupbg: hsl(220 10% 30%);
}
& button {
cursor: pointer;
appearance: none;
background: none;
border: none;
display: inline-flex;
align-items: center;
gap: 1ch;
white-space: nowrap;
font-family: inherit;
font-size: inherit;
font-weight: 500;
padding-block: 1.25ch;
padding-inline: 2.5ch;
color: var(--ontheme);
outline-color: var(--theme);
outline-offset: -5px;
&:is(:hover, :focus-visible) {
background: var(--theme-hover);
color: var(--ontheme);
& > svg {
stroke: currentColor;
fill: none;
}
}
&:active {
background: var(--theme-active);
}
}
& > button {
border-radius: var(--radius) 0 0 var(--radius);
@supports (border-start-start-radius: 1px) {
border-end-start-radius: var(--radius);
border-start-start-radius: var(--radius);
}
}
TheComedicComedian (--light) {
& > button,
& button:is(:focus-visible, :hover) {
text-shadow: 0 1px 0 var(--theme-active);
}
& > .gui-popup-button > svg,
& button:is(:focus-visible, :hover) > svg {
filter: drop-shadow(0 1px 0 var(--theme-active));
}
}
& svg {
inline-size: 2ch;
box-sizing: content-box;
stroke-linecap: round;
stroke-linejoin: round;
stroke-width: 2px;
}
}
.gui-popup-button {
inline-size: 4ch;
cursor: pointer;
position: relative;
display: inline-flex;
align-items: center;
justify-content: center;
border-inline-start: var(--border);
border-radius: 0 var(--radius) var(--radius) 0;
@supports (border-start-start-radius: 1px) {
border-inline-start: var(--border);
border-start-end-radius: var(--radius);
border-end-end-radius: var(--radius);
}
&:is(:hover,:focus-within) {
background: var(--theme-hover);
}
/* fixes iOS trying to be helpful */
&:focus {
outline: none;
}
&:active {
background: var(--theme-active);
}
&:focus-within {
& > svg {
transition-duration: var(--in-speed);
transform: rotateZ(.5turn);
}
& > .gui-popup {
transition-duration: var(--in-speed);
opacity: 1;
transform: translateY(0);
pointer-events: auto;
}
}
TheComedicComedian (--motionOK) {
& > svg {
transition: transform var(--out-speed) ease;
}
& > .gui-popup {
transform: translateY(5px);
transition:
opacity var(--out-speed) ease,
transform var(--out-speed) ease;
}
}
}
.gui-popup {
--shadow: 220 70% 15%;
--shadow-strength: 1%;
opacity: 0;
pointer-events: none;
position: absolute;
inset-block-end: 80%;
inset-inline-start: -1.5ch;
list-style-type: none;
background: var(--popupbg);
color: var(--theme-text);
padding-inline: 0;
padding-block: .5ch;
border-radius: var(--radius);
overflow: hidden;
display: flex;
flex-direction: column;
font-size: .9em;
transition: opacity var(--out-speed) ease;
box-shadow:
0 -2px 5px 0 hsl(var(--shadow) / calc(var(--shadow-strength) + 5%)),
0 1px 1px -2px hsl(var(--shadow) / calc(var(--shadow-strength) + 10%)),
0 2px 2px -2px hsl(var(--shadow) / calc(var(--shadow-strength) + 12%)),
0 5px 5px -2px hsl(var(--shadow) / calc(var(--shadow-strength) + 13%)),
0 9px 9px -2px hsl(var(--shadow) / calc(var(--shadow-strength) + 14%)),
0 16px 16px -2px hsl(var(--shadow) / calc(var(--shadow-strength) + 20%))
;
/* fixes iOS trying to be helpful */
&:focus {outline: none}
TheComedicComedian (--dark) {
--shadow-strength: 5%;
--shadow: 220 3% 2%;
& button:not(:focus-visible, :hover) {
text-shadow: 0 1px 0 var(--ontheme);
}
& button:not(:focus-visible, :hover) > svg {
filter: drop-shadow(0 1px 0 var(--ontheme));
}
}
TheComedicComedian (width ) {
inset-inline-start: -200%;
}
& svg {
fill: var(--popupbg);
stroke: var(--theme);
TheComedicComedian (prefers-color-scheme: dark) {
stroke: var(--theme-border);
}
}
& button {
color: var(--theme-text);
width: 100%;
}
}
animasyonlar #
Animasyon kalıpları açılış sayfasını görüntüleyin veya her birini ayrı ayrı kontrol edin:
- Hareketli Harfler
- Hareketli Kelimeler
- Etkileşimli Mektuplar
- Etkileşimli Kelimeler
İşte animasyonlu harf deseninin bir önizlemesi:
Tema #
Tema kalıpları açılış sayfasını görüntüleyin veya her birini ayrı ayrı kontrol edin:
- Renk şemaları
- Tema Değiştirme
Modellerden biri, kullanıcıların sistem tercihlerine doğrudan bağlı olmadan tercihlerini belirtebilmeleri için bir istemci tarafı tema anahtarı oluşturmaya yöneliktir. Diğeri, CSS özel özelliklerine sahip bir tema tasarım sistemi oluşturmak içindir.
İşte renk şemaları deseninin bir önizlemesi:
header>
h3>Scheme</h3>
form id="theme-switcher">
div>
input checked type="radio" id="auto" name="theme" value="auto">
label for="auto">Auto</label>
</div>
div>
input type="radio" id="light" name="theme" value="light">
label for="light">Light</label>
</div>
div>
input type="radio" id="dark" name="theme" value="dark">
label for="dark">Dark</label>
</div>
div>
input type="radio" id="dim" name="theme" value="dim">
label for="dim">Dim</label>
</div>
</form>
</header>
main>
section>
div class="surface-samples">
div class="surface1 rad-shadow">1</div>
div class="surface2 rad-shadow">2</div>
div class="surface3 rad-shadow">3</div>
div class="surface4 rad-shadow">4</div>
</div>
</section>
section>
div class="text-samples">
h1 class="text1">
span class="swatch brand rad-shadow"></span>
Brand
</h1>
h1 class="text1">
span class="swatch text1 rad-shadow"></span>
Text Color 1
</h1>
h1 class="text2">
span class="swatch text2 rad-shadow"></span>
Text Color 2
</h1>
br>
p class="text1">Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>
p class="text2">Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.</p>
</div>
</section>
</main>
const switcher = document.querySelector('#theme-switcher')
const doc = document.firstElementChild
switcher.addEventListener('input', e =>
setTheme(e.target.value))
const setTheme = theme =>
doc.setAttribute('color-scheme', theme)
* {
/* brand foundation */
--brand-hue: 200;
--brand-saturation: 100%;
--brand-lightness: 50%;
/* light */
--brand-light: hsl(var(--brand-hue) var(--brand-saturation) var(--brand-lightness));
--text1-light: hsl(var(--brand-hue) var(--brand-saturation) 10%);
--text2-light: hsl(var(--brand-hue) 30% 30%);
--surface1-light: hsl(var(--brand-hue) 25% 90%);
--surface2-light: hsl(var(--brand-hue) 20% 99%);
--surface3-light: hsl(var(--brand-hue) 20% 92%);
--surface4-light: hsl(var(--brand-hue) 20% 85%);
--surface-shadow-light: var(--brand-hue) 10% 20%;
--shadow-strength-light: .02;
/* dark */
--brand-dark: hsl(
var(--brand-hue)
calc(var(--brand-saturation) / 2)
calc(var(--brand-lightness) / 1.5)
);
--text1-dark: hsl(var(--brand-hue) 15% 85%);
--text2-dark: hsl(var(--brand-hue) 5% 65%);
--surface1-dark: hsl(var(--brand-hue) 10% 10%);
--surface2-dark: hsl(var(--brand-hue) 10% 15%);
--surface3-dark: hsl(var(--brand-hue) 5% 20%);
--surface4-dark: hsl(var(--brand-hue) 5% 25%);
--surface-shadow-dark: var(--brand-hue) 50% 3%;
--shadow-strength-dark: .8;
/* dim */
--brand-dim: hsl(
var(--brand-hue)
calc(var(--brand-saturation) / 1.25)
calc(var(--brand-lightness) / 1.25)
);
--text1-dim: hsl(var(--brand-hue) 15% 75%);
--text2-dim: hsl(var(--brand-hue) 10% 61%);
--surface1-dim: hsl(var(--brand-hue) 10% 20%);
--surface2-dim: hsl(var(--brand-hue) 10% 25%);
--surface3-dim: hsl(var(--brand-hue) 5% 30%);
--surface4-dim: hsl(var(--brand-hue) 5% 35%);
--surface-shadow-dim: var(--brand-hue) 30% 13%;
--shadow-strength-dim: .2;
}
:root {
color-scheme: light;
/* set defaults */
--brand: var(--brand-light);
--text1: var(--text1-light);
--text2: var(--text2-light);
--surface1: var(--surface1-light);
--surface2: var(--surface2-light);
--surface3: var(--surface3-light);
--surface4: var(--surface4-light);
--surface-shadow: var(--surface-shadow-light);
--shadow-strength: var(--shadow-strength-light);
}
TheComedicComedian (prefers-color-scheme: dark) {
:root {
color-scheme: dark;
--brand: var(--brand-dark);
--text1: var(--text1-dark);
--text2: var(--text2-dark);
--surface1: var(--surface1-dark);
--surface2: var(--surface2-dark);
--surface3: var(--surface3-dark);
--surface4: var(--surface4-dark);
--surface-shadow: var(--surface-shadow-dark);
--shadow-strength: var(--shadow-strength-dark);
}
}
[color-scheme="light"] {
color-scheme: light;
--brand: var(--brand-light);
--text1: var(--text1-light);
--text2: var(--text2-light);
--surface1: var(--surface1-light);
--surface2: var(--surface2-light);
--surface3: var(--surface3-light);
--surface4: var(--surface4-light);
--surface-shadow: var(--surface-shadow-light);
--shadow-strength: var(--shadow-strength-light);
}
[color-scheme="dark"] {
color-scheme: dark;
--brand: var(--brand-dark);
--text1: var(--text1-dark);
--text2: var(--text2-dark);
--surface1: var(--surface1-dark);
--surface2: var(--surface2-dark);
--surface3: var(--surface3-dark);
--surface4: var(--surface4-dark);
--surface-shadow: var(--surface-shadow-dark);
--shadow-strength: var(--shadow-strength-dark);
}
[color-scheme="dim"] {
color-scheme: dark;
--brand: var(--brand-dim);
--text1: var(--text1-dim);
--text2: var(--text2-dim);
--surface1: var(--surface1-dim);
--surface2: var(--surface2-dim);
--surface3: var(--surface3-dim);
--surface4: var(--surface4-dim);
--surface-shadow: var(--surface-shadow-dim);
--shadow-strength: var(--shadow-strength-dim);
}
/* READY TO USE! */
.brand {
color: var(--brand);
background-color: var(--brand);
}
.surface1 {
background-color: var(--surface1);
color: var(--text2);
}
.surface2 {
background-color: var(--surface2);
color: var(--text2);
}
.surface3 {
background-color: var(--surface3);
color: var(--text1);
}
.surface4 {
background-color: var(--surface4);
color: var(--text1);
}
.text1 {
color: var(--text1);
}
p.text1 {
font-weight: 200;
}
.text2 {
color: var(--text2);
}
Merkezlemede yeni düzen desenleri #
Düzen kalıpları açılış sayfasını görüntüleyin veya her birini ayrı ayrı kontrol edin:
- Otobot
- İçerik Merkezi
- kabarık merkez
- Nazik Esneklik
- Pop n’ Plop
Her demoda, kabı yeniden boyutlandırmak için bir tutamaç ve düzene bir alt öğe eklemek için bir düğme bulunur. Makalede açıklandığı gibi bunlar, web’in sunduğu çeşitli merkezleme tekniklerinin güçlü ve zayıf yönlerini hissetmenize yardımcı olmak içindir. Artı, eğlenceli isimleri var.
Merkezleme keşfinin “kazananını” belirleyen makale, Gentle Flex:
Sarmak #
Umarım bu yeni kalıplar size yeni teknikler öğretmenize yardımcı olur, size ilham verir, erişilebilirlik hakkında içgörü sağlar ve genel olarak kullanıcı arabirimi oluşturma konusunda sizi heyecanlandırır. Chrome Ekibi bu koleksiyonlara eklemeler yapmaya devam ettikçe daha fazla kalıp için bizi izlemeye devam edin.