Bu gönderide, renklerle uyumlu ve erişilebilir bir tasarımın nasıl oluşturulacağına ilişkin düşüncelerimi paylaşmak istiyorum. <tool-tip>
özel öğe. Demoyu deneyin Ve kaynağı görüntüle!
Videoyu tercih ederseniz, işte bu gönderinin bir YouTube versiyonu:
genel bakış #
Bir araç ipucu, kullanıcı arabirimleri için ek bilgiler içeren, kipli olmayan, engellemeyen, etkileşimli olmayan bir yer paylaşımıdır. Varsayılan olarak gizlidir ve ilişkili bir öğe üzerine gelindiğinde veya odaklanıldığında görünür hale gelir. Bir araç ipucu doğrudan seçilemez veya onunla etkileşim kurulamaz. Araç ipuçları, etiketlerin veya diğer yüksek değerli bilgilerin yerine geçmez; bir kullanıcı, bir araç ipucu olmadan görevini tam olarak tamamlayabilmelidir.
Yapmayın: Etiketler yerine araç ipuçlarına güvenmeyin
Toggletip ve Araç İpucu #
Birçok bileşen gibi, bir araç ipucunun ne olduğuna dair çeşitli açıklamalar vardır, örneğin MDN, ARYA SUYU, sarah higleyVe Kapsamlı Bileşenler. Araç ipuçları ve geçiş ipuçları arasındaki ayrımı seviyorum. Bir araç ipucu, etkileşimli olmayan ek bilgiler içermelidir, bir geçiş ipucu ise etkileşim ve önemli bilgiler içerebilir. Bölünmenin birincil nedeni erişilebilirlik, kullanıcıların açılır pencereye nasıl gitmeleri ve içindeki bilgilere ve düğmelere nasıl erişmelerinin beklendiğidir. Geçiş ipuçları hızla karmaşıklaşır.
İşte bir geçiş ipucunun videosu tasarım odası alan; kullanıcının sabitleyip açıp keşfedebileceği, ardından hafifçe kapatarak veya kaçış tuşuyla kapatabileceği etkileşimli bir yer paylaşımı:
Bu GUI Mücadelesi, CSS ile neredeyse her şeyi yapmak isteyen bir araç ipucu rotasına gitti ve işte bunu nasıl oluşturacağınız.
işaretleme #
Özel bir öğe kullanmayı seçtim <tool-tip>
. Yazarların, istemiyorlarsa özel öğeleri web bileşenlerine dönüştürmeleri gerekmez. Tarayıcı tedavi edecek <foo-bar>
tıpkı bir gibi <div>
. Daha az özgüllüğe sahip bir sınıf adı gibi özel bir öğe düşünebilirsiniz. JavaScript dahil değildir.
tool-tip>A tooltip</tool-tip>
Bu, içinde bazı metinler bulunan bir div gibidir. Yetenekli ekran okuyucuların erişilebilirlik ağacına şunu ekleyerek bağlanabiliriz: [role="tooltip"]
.
tool-tip role="tooltip">A tooltip</tool-tip>
Şimdi, tarama okuyucuları için bir araç ipucu olarak kabul ediliyor. Aşağıdaki örnekte, ilk bağlantı öğesinin ağacında nasıl tanınan bir araç ipucu öğesine sahip olduğunu ve ikincisinin nasıl olmadığını görün. İkincisinin rolü yok. Stiller bölümünde bu ağaç görünümünü geliştireceğiz.
Ardından, odaklanılabilir olmamak için araç ipucuna ihtiyacımız var. Bir ekran okuyucu araç ipucu rolünü anlamıyorsa, kullanıcıların <tool-tip>
içeriği okumak için ve kullanıcı deneyimi buna ihtiyaç duymaz. Ekran okuyucular, içeriği üst öğeye ekler ve bu nedenle, erişilebilir hale getirilmesi için odaklanmaya gerek yoktur. Burada kullanabiliriz inert
hiçbir kullanıcının yanlışlıkla bu araç ipucu içeriğini sekme akışında bulmamasını sağlamak için:
tool-tip inert role="tooltip">A tooltip</tool-tip>
Daha sonra, araç ipucunun konumunu belirtmek için nitelikleri arayüz olarak kullanmayı seçtim. varsayılan olarak tüm <tool-tip>
s bir “üst” konum alacaktır, ancak konum, bir öğe üzerinde eklenerek özelleştirilebilir. tip-position
:
tool-tip role="tooltip" tip-position="right ">A tooltip</tool-tip>
Bunun gibi şeyler için sınıflar yerine nitelikleri kullanma eğilimindeyim, böylece <tool-tip>
kendisine aynı anda birden fazla pozisyon atanamaz. Sadece bir tane olabilir veya hiç olmayabilir.
Son olarak, yer <tool-tip>
araç ipucu sağlamak istediğiniz öğenin içindeki öğeler. İşte paylaşıyorum alt
bir resim ve bir resim yerleştirerek gören kullanıcılarla metin <tool-tip>
içinde bir <picture>
öğe:
picture>
img alt="The GUI Challenges skull logo" width="100" src="...">
tool-tip role="tooltip" tip-position="bottom">
The b>GUI Challenges</b> skull logo
</tool-tip>
</picture>
buraya bir yerleştiriyorum <tool-tip>
içinde bir <abbr>
öğe:
p>
The abbr>HTML tool-tip role="tooltip" tip-position="top">Hyper Text Markup Language</tool-tip></abbr> abbr element.
</p>
Ulaşılabilirlik #
Geçiş ipuçlarını değil, araç ipuçlarını oluşturmayı seçtiğim için, bu bölüm çok daha basit. Öncelikle, arzu ettiğimiz kullanıcı deneyiminin ana hatlarını vereyim:
- Kısıtlı alanlarda veya karmaşık arayüzlerde ek mesajları gizleyin.
- Bir kullanıcı bir öğeyle etkileşim kurmak için fareyle üzerine geldiğinde, odaklandığında veya dokunmayı kullandığında, mesajı gösterin.
- Fareyle üzerine gelme, odaklanma veya dokunma sona erdiğinde mesajı tekrar gizleyin.
- Son olarak, bir kullanıcı azaltılmış hareket için bir tercih belirlediyse, tüm hareketlerin azaltıldığından emin olun.
Amacımız talep üzerine ek mesajlaşmadır. Gören bir fare veya klavye kullanıcısı, mesajı gözleriyle okuyarak ortaya çıkarmak için üzerine gelebilir. Göremeyen bir ekran okuyucu kullanıcısı, aracı aracılığıyla işitsel olarak alarak mesajı ortaya çıkarmak için odaklanabilir.
Bir önceki bölümde erişilebilirlik ağacını, araç ipucu rolünü ele aldık ve inert, geriye kalan onu test etmek ve kullanıcı deneyiminin kullanıcıya araç ipucu mesajını uygun şekilde gösterdiğini doğrulamak. Testin ardından, sesli mesajın hangi bölümünün bir araç ipucu olduğu net değil. Erişilebilirlik ağacında da hata ayıklanırken görülebiliyor, “top” link metni “Bak, tooltips!” ile birlikte hiç tereddüt etmeden çalıştırılıyor. Ekran okuyucu, metni araç ipucu içeriği olarak bozmaz veya tanımlamaz.
Yalnızca ekran okuyucuya sözde öğe ekleyin <tool-tip>
ve göremeyen kullanıcılar için kendi istem metnimizi ekleyebiliriz.
&::before {
content: "; Has tooltip: ";
clip: rect(1px, 1px, 1px, 1px);
clip-path: inset(50%);
height: 1px;
width: 1px;
margin: -1px;
overflow: hidden;
padding: 0;
position: absolute;
}
Aşağıda, artık bağlantı metninden sonra bir noktalı virgül ve “İpucu var: ” araç ipucu için bir istem içeren güncellenmiş erişilebilirlik ağacını görebilirsiniz.
Şimdi, bir ekran okuyucu kullanıcısı bağlantıya odaklandığında, “üst” diyor ve kısa bir duraklama alıyor, ardından “araç ipucu var: bak, araç ipuçları” duyurusu yapıyor. Bu, bir ekran okuyucu kullanıcısına birkaç hoş UX ipucu verir. Tereddüt, bağlantı metni ile araç ipucu arasında güzel bir ayrım sağlar. Ayrıca, “araç ipucu var” duyurusu yapıldığında, bir ekran okuyucu kullanıcısı bunu daha önce duyduysa kolayca iptal edebilir. Ek mesajı daha önce gördüğünüz gibi, hızla gezinmeyi ve gezinmeyi çok anımsatıyor. Bu güzel bir UX paritesi gibi geldi.
stiller #
bu <tool-tip>
öğesi, ek mesajlaşmayı temsil ettiği öğenin alt öğesi olacaktır, bu nedenle önce bindirme efekti için temel bilgilerle başlayalım. İle belge akışının dışına çıkarın position absolute
:
tool-tip {
position: absolute;
z-index: 1;
}
Ebeveyn bir yığın bağlamı değilse, araç ipucu kendisini en yakın olana konumlandıracaktır ki bu bizim istediğimiz şey değildir. Blokta yardımcı olabilecek yeni bir seçici var, :has()
:
- Chrome 105, Desteklenir 105
- Firefox 103, Bir bayrağın arkasında
- Kenar 105, Desteklenen 105
- Safari 15.4, Desteklenir 15.4
:has(> tool-tip) {
position: relative;
}
Tarayıcı desteği hakkında çok fazla endişelenmeyin. Öncelikle, bu araç ipuçlarının tamamlayıcı olduğunu unutmayın. Çalışmıyorlarsa, iyi olmalı. İkinci olarak, JavaScript bölümünde, tarayıcılar için ihtiyaç duyduğumuz işlevselliği çoklu doldurmak için bir komut dosyası dağıtacağız. :has()
Destek.
Ardından, ana öğelerinden işaretçi olaylarını çalmamaları için araç ipuçlarını etkileşimli hale getirelim:
tool-tip {
…
pointer-events: none;
user-select: none;
}
Ardından, araç ipucunu bir crossfade ile değiştirebilmemiz için araç ipucunu opaklıkla gizleyin:
tool-tip {
opacity: 0;
}:has(> tool-tip):is(:hover, :focus-visible, :active) > tool-tip {
opacity: 1;
}
:is()
Ve :has()
burada ağır kaldırma yapmak, yapmak tool-tip
Bir alt araç ipucunun görünürlüğünü değiştirmek için kullanıcı etkileşiminden haberdar olan üst öğeler içeren. Fare kullanıcıları üzerine gelebilir, klavye ve ekran okuyucu kullanıcıları odaklanabilir ve dokunmatik kullanıcılar dokunabilir.
Görebilen kullanıcılar için çalışan göster ve gizle kaplamasıyla, tema oluşturmak, konumlandırmak ve balona üçgen şekli eklemek için bazı stiller eklemenin zamanı geldi. Aşağıdaki stiller, özel özellikleri kullanmaya başlar, şu ana kadar bulunduğumuz noktayı temel alır ve aynı zamanda kayan bir araç ipucu gibi görünmesi için gölgeler, tipografi ve renkler ekler:
tool-tip {
--_p-inline: 1.5ch;
--_p-block: .75ch;
--_triangle-size: 7px;
--_bg: hsl(0 0% 20%);
--_shadow-alpha: 50%;--_bottom-tip: conic-gradient(from -30deg at bottom, rgba(0,0,0,0), #000 1deg 60deg, rgba(0,0,0,0) 61deg) bottom / 100% 50% no-repeat;
--_top-tip: conic-gradient(from 150deg at top, rgba(0,0,0,0), #000 1deg 60deg, rgba(0,0,0,0) 61deg) top / 100% 50% no-repeat;
--_right-tip: conic-gradient(from -120deg at right, rgba(0,0,0,0), #000 1deg 60deg, rgba(0,0,0,0) 61deg) right / 50% 100% no-repeat;
--_left-tip: conic-gradient(from 60deg at left, rgba(0,0,0,0), #000 1deg 60deg, rgba(0,0,0,0) 61deg) left / 50% 100% no-repeat;
pointer-events: none;
user-select: none;
opacity: 0;
transform: translateX(var(--_x, 0)) translateY(var(--_y, 0));
transition: opacity .2s ease, transform .2s ease;
position: absolute;
z-index: 1;
inline-size: max-content;
max-inline-size: 25ch;
text-align: start;
font-size: 1rem;
font-weight: normal;
line-height: normal;
line-height: initial;
padding: var(--_p-block) var(--_p-inline);
margin: 0;
border-radius: 5px;
background: var(--_bg);
color: CanvasText;
will-change: filter;
filter:
drop-shadow(0 3px 3px hsl(0 0% 0% / var(--_shadow-alpha)))
drop-shadow(0 12px 12px hsl(0 0% 0% / var(--_shadow-alpha)));
}
/* create a stacking context for elements with > tool-tips */
:has(> tool-tip) {
position: relative;
}
/* when those parent elements have focus, hover, etc */
:has(> tool-tip):is(:hover, :focus-visible, :active) > tool-tip {
opacity: 1;
transition-delay: 200ms;
}
/* prepend some prose for screen readers only */
tool-tip::before {
content: "; Has tooltip: ";
clip: rect(1px, 1px, 1px, 1px);
clip-path: inset(50%);
height: 1px;
width: 1px;
margin: -1px;
overflow: hidden;
padding: 0;
position: absolute;
}
/* tooltip shape is a pseudo element so we can cast a shadow */
tool-tip::after {
content: "";
background: var(--_bg);
position: absolute;
z-index: -1;
inset: 0;
mask: var(--_tip);
}
/* top tooltip styles */
tool-tip:is(
[tip-position="top"],
[tip-position="block-start"],
:not([tip-position]),
[tip-position="bottom"],
[tip-position="block-end"]
) {
text-align: center;
}
Tema ayarlamaları #
Metin rengi sistem anahtar kelimesi aracılığıyla sayfadan devralındığından, araç ipucunun yönetilmesi gereken yalnızca birkaç rengi vardır. CanvasText
. Ayrıca, değerleri depolamak için özel özellikler yaptığımız için, yalnızca bu özel özellikleri güncelleyebilir ve gerisini temanın halletmesine izin verebiliriz:
TheComedicComedian (prefers-color-scheme: light) {
tool-tip {
--_bg: white;
--_shadow-alpha: 15%;
}
}
Açık tema için arka planı beyaza uyarlıyoruz ve opaklıklarını ayarlayarak gölgeleri çok daha az güçlü hale getiriyoruz.
Sağdan sola #
Sağdan sola okuma modlarını desteklemek için, özel bir özellik belge yönünün değerini sırasıyla -1 veya 1 değerinde depolar.
tool-tip {
--isRTL: -1;
}tool-tip:dir(rtl) {
--isRTL: 1;
}
Bu, araç ipucunun konumlandırılmasına yardımcı olmak için kullanılabilir:
tool-tip[tip-position="top"]) {
--_x: calc(50% * var(--isRTL));
}
Üçgenin nerede olduğu konusunda yardımcı olmanın yanı sıra:
tool-tip[tip-position="right"]::after {
--_tip: var(--_left-tip);
}tool-tip[tip-position="right"]:dir(rtl)::after {
--_tip: var(--_right-tip);
}
Son olarak, mantıksal dönüşümler için de kullanılabilir. translateX()
:
--_x: calc(var(--isRTL) * -3px * -1);
Araç ipucu konumlandırma #
Araç ipucunu mantıksal olarak konumlandırın. inset-block
veya inset-inline
hem fiziksel hem de mantıksal araç ipucu konumlarını işlemek için özellikler. Aşağıdaki kod, dört konumun her birinin hem soldan sağa hem de sağdan sola yönler için nasıl biçimlendirildiğini gösterir.
Üst ve blok başlangıç hizalaması #
tool-tip:is([tip-position="top"], [tip-position="block-start"], :not([tip-position])) {
inset-inline-start: 50%;
inset-block-end: calc(100% + var(--_p-block) + var(--_triangle-size));
--_x: calc(50% * var(--isRTL));
}tool-tip:is([tip-position="top"], [tip-position="block-start"], :not([tip-position]))::after {
--_tip: var(--_bottom-tip);
inset-block-end: calc(var(--_triangle-size) * -1);
border-block-end: var(--_triangle-size) solid transparent;
}
Sağ ve satır içi hizalama #
tool-tip:is([tip-position="right"], [tip-position="inline-end"]) {
inset-inline-start: calc(100% + var(--_p-inline) + var(--_triangle-size));
inset-block-end: 50%;
--_y: 50%;
}tool-tip:is([tip-position="right"], [tip-position="inline-end"])::after {
--_tip: var(--_left-tip);
inset-inline-start: calc(var(--_triangle-size) * -1);
border-inline-start: var(--_triangle-size) solid transparent;
}
tool-tip:is([tip-position="right"], [tip-position="inline-end"]):dir(rtl)::after {
--_tip: var(--_right-tip);
}
Alt ve blok ucu hizalaması #
tool-tip:is([tip-position="bottom"], [tip-position="block-end"]) {
inset-inline-start: 50%;
inset-block-start: calc(100% + var(--_p-block) + var(--_triangle-size));
--_x: calc(50% * var(--isRTL));
}tool-tip:is([tip-position="bottom"], [tip-position="block-end"])::after {
--_tip: var(--_top-tip);
inset-block-start: calc(var(--_triangle-size) * -1);
border-block-start: var(--_triangle-size) solid transparent;
}
Sol ve satır içi başlangıç hizalaması #
tool-tip:is([tip-position="left"], [tip-position="inline-start"]) {
inset-inline-end: calc(100% + var(--_p-inline) + var(--_triangle-size));
inset-block-end: 50%;
--_y: 50%;
}tool-tip:is([tip-position="left"], [tip-position="inline-start"])::after {
--_tip: var(--_right-tip);
inset-inline-end: calc(var(--_triangle-size) * -1);
border-inline-end: var(--_triangle-size) solid transparent;
}
tool-tip:is([tip-position="left"], [tip-position="inline-start"]):dir(rtl)::after {
--_tip: var(--_left-tip);
}
Animasyon #
Şimdiye kadar yalnızca araç ipucunun görünürlüğünü değiştirdik. Genel olarak güvenli, azaltılmış hareket geçişi olduğundan, bu bölümde önce tüm kullanıcılar için opaklığı canlandıracağız. Ardından, araç ipucunun ana öğeden dışarı kaymış gibi görünmesi için dönüştürme konumunu canlandıracağız.
Güvenli ve anlamlı bir varsayılan geçiş #
Geçiş opaklığı ve dönüşümü için araç ipucu öğesini şu şekilde biçimlendirin:
tool-tip {
opacity: 0;
transform: translateX(var(--_x, 0)) translateY(var(--_y, 0));
transition: opacity .2s ease, transform .2s ease;
}:has(> tool-tip):is(:hover, :focus-visible, :active) > tool-tip {
opacity: 1;
transition-delay: 200ms;
}
Geçişe hareket ekleme #
Bir araç ipucunun görünebileceği kenarların her biri için, kullanıcı hareket konusunda uygunsa, translateX özelliğini seyahat etmesi için küçük bir mesafe vererek hafifçe konumlandırın:
TheComedicComedian (prefers-reduced-motion: no-preference) {
:has(> tool-tip:is([tip-position="top"], [tip-position="block-start"], :not([tip-position]))):not(:hover):not(:focus-visible):not(:active) tool-tip {
--_y: 3px;
}:has(> tool-tip:is([tip-position="right"], [tip-position="inline-end"])):not(:hover):not(:focus-visible):not(:active) tool-tip {
--_x: -3px;
}
:has(> tool-tip:is([tip-position="bottom"], [tip-position="block-end"])):not(:hover):not(:focus-visible):not(:active) tool-tip {
--_y: -3px;
}
:has(> tool-tip:is([tip-position="left"], [tip-position="inline-start"])):not(:hover):not(:focus-visible):not(:active) tool-tip {
--_x: 3px;
}
}
“Giriş” durumu konumunda olduğundan, bunun “çıkış” durumunu ayarladığına dikkat edin. translateX(0)
.
JavaScript #
Bence, JavaScript isteğe bağlıdır. Bunun nedeni, kullanıcı arabiriminizde bir görevi gerçekleştirmek için bu araç ipuçlarından hiçbirinin okunması gerekmemesidir. Bu nedenle, araç ipuçları tamamen başarısız olursa, önemli bir şey olmamalıdır. Bu aynı zamanda araç ipuçlarını aşamalı olarak geliştirilmiş olarak değerlendirebileceğimiz anlamına gelir. Sonunda tüm tarayıcılar destekleyecektir :has()
ve bu komut dosyası tamamen ortadan kalkabilir.
Polyfill komut dosyası iki şey yapar ve bunu yalnızca tarayıcı desteklemiyorsa yapar. :has()
. İlk olarak, kontrol edin :has()
Destek:
if (!CSS.supports('selector(:has(*))')) {
// do work
}
Ardından, ana öğelerini bulun <tool-tip>
s ve onlara çalışacakları bir sınıf adı verin:
if (!CSS.supports('selector(:has(*))')) {
document.querySelectorAll('tool-tip').forEach(tooltip =>
tooltip.parentNode.classList.add('has_tool-tip'))
}
Ardından, bu sınıf adını kullanan bir dizi stil enjekte ederek, :has()
tam olarak aynı davranış için seçici:
if (!CSS.supports('selector(:has(*))')) {
document.querySelectorAll('tool-tip').forEach(tooltip =>
tooltip.parentNode.classList.add('has_tool-tip'))let styles = document.createElement('style')
styles.textContent = `
.has_tool-tip {
position: relative;
}
.has_tool-tip:is(:hover, :focus-visible, :active) > tool-tip {
opacity: 1;
transition-delay: 200ms;
}
`
document.head.appendChild(styles)
}
İşte bu, artık tüm tarayıcılar araç ipuçlarını mutlu bir şekilde gösterecektir. :has()
desteklenmiyor.
Çözüm #
Artık nasıl yaptığımı bildiğine göre, nasıl yapardın‽ 🙂 Gerçekten sabırsızlıkla bekliyorum popup
Geçiş ipuçlarını kolaylaştırmak için API, Üst tabaka z-endeksi olmayan savaşlar için ve anchor
Nesneleri pencerede daha iyi konumlandırmak için API. O zamana kadar araç ipuçları yapacağım.
Yaklaşımlarımızı çeşitlendirelim ve web üzerinde oluşturmanın tüm yollarını öğrenelim.
Bir demo oluşturun, beni tweetle bağlantılar ve onu aşağıdaki topluluk remiksleri bölümüne ekleyeceğim!
Topluluk remiksleri #
Burada henüz görülecek bir şey yok.