Bu kılavuz kimin için?
Web arayüzü (UI) tasarımı, bir sayfanın nasıl göründüğü kadar nasıl kullanıldığıyla da ilgilidir: hangi öğenin önce okunacağı, bir düğmenin tıklanabilir olduğunun nasıl anlaşılacağı, bir formun hata verdiğinde kullanıcıya ne söyleyeceği. Bu yazı, tasarımcılar ile ön yüz (front-end) geliştiricilerinin ortak dili olabilecek somut kuralları topluyor: ızgara ve boşluk sistemi, tipografi ölçeği, renk ve kontrast, bileşen durumları, formlar, duyarlı (responsive) düzen, sık yapılan hatalar ve yayından önce tasarım kontrolü. Kuralların çoğu sayıyla ifade edilir; böylece "biraz daha ferah olsun" yerine "boşluk 16 pikselden 24 piksele çıksın" diye konuşulur.Bu kuralları ekipler arasında yaşatmak, tasarım sistemleri ve Figma'dan koda tasarım teslimi (handoff) yazılarımızın konusu.
Izgara (grid) ve boşluk sistemi
Düzenli görünen arayüzlerin sırrı, her ölçünün küçük bir ölçekten seçilmesidir. Yaygın yaklaşım 4 ya da 8 piksellik bir taban birimidir: boşluklar 4, 8, 12, 16, 24, 32, 48, 64 gibi değerlerden seçilir, araya keyfî 13 ya da 22 piksel girmez.- Kapsayıcı (container): Metin ağırlıklı sayfalarda içerik genişliği okunabilirlik için sınırlanır; tablolar ve panolar daha geniş bir kapsayıcı kullanabilir. Kenar boşlukları (gutter) mobilde 16, tablette 24, masaüstünde 32 piksel gibi kırılma noktasına göre büyür.
- Sütun ızgarası: Masaüstünde 12, tablette 8, mobilde 4 sütun yaygın bir başlangıçtır. Izgara bir kısıt değil, hizalama aracıdır; önemli olan sayfadaki her bloğun aynı sol ve sağ çizgiye oturmasıdır.
- Yakınlık (proximity): Birbiriyle ilgili öğeler arasındaki boşluk, ilgisiz gruplar arasındakinden belirgin biçimde küçük olmalıdır: etiketle alanı arasında 4-8 piksel, form grupları arasında 24-32 piksel gibi.
Code:
:root {
--space-1: 4px; --space-2: 8px; --space-3: 12px; --space-4: 16px;
--space-5: 24px; --space-6: 32px; --space-7: 48px; --space-8: 64px;
--gutter: var(--space-4);
}
@media (min-width: 768px) { :root { --gutter: var(--space-5); } }
@media (min-width: 1200px) { :root { --gutter: var(--space-6); } }
.container {
max-width: 1200px;
margin-inline: auto;
padding-inline: var(--gutter);
}
Tipografi: ölçek, satır uzunluğu, akışkan boyut
Metin, arayüzün büyük kısmını oluşturur; birkaç kural okunabilirliği belirgin biçimde artırır:- Gövde metni: Tarayıcıların varsayılan boyutu olan 16 piksel, yaygın kabul gören alt sınırdır; uzun okumalarda 17-18 piksel daha rahattır. Satır yüksekliği gövdede 1,4-1,6, başlıklarda 1,1-1,3 arasında tutulur.
- Satır uzunluğu: Yaygın öneri satır başına 45-75 karakterdir. CSS'te max-width: 70ch gibi bir sınır bunu kolaylaştırır.
- Ölçek: Başlık boyutları sabit bir oranla büyür (ör. 1,2 ya da 1,25). Altı farklı başlık boyutu yerine üç-dört düzey çoğu site için yeterlidir.
- Akışkan boyut (fluid typography): Başlıkları ekran genişliğiyle büyütmek için clamp() kullanın. Yalnızca vw birimiyle verilen boyutlar tarayıcı yakınlaştırmasıyla büyümez; W3C bunu, metnin %200'e kadar büyütülebilmesini isteyen 1.4.4 ölçütü için bir hata örneği (F94) olarak listeler. Bu yüzden rem ile vw'yi birlikte kullanın.
Code:
body { font-size: 1rem; line-height: 1.5; }
h1 { font-size: clamp(1.75rem, 1.2rem + 2.2vw, 2.75rem); line-height: 1.15; }
h2 { font-size: clamp(1.375rem, 1.1rem + 1.1vw, 1.875rem); line-height: 1.2; }
.prose { max-width: 70ch; }
Renk ve kontrast: WCAG 2.2 eşikleri
WCAG 2.2, 5 Ekim 2023'te W3C tavsiyesi (Recommendation) olarak yayımlandı; w3.org'daki güncel metin 12 Aralık 2024 tarihlidir. Çoğu kurumun hedeflediği AA düzeyinde kontrast eşikleri şöyledir:| Öğe | En az kontrast | Ölçüt |
|---|---|---|
| Normal metin | 4,5:1 | 1.4.3 |
| Büyük metin (18 punto ya da 14 punto kalın; yaklaşık 24 px ya da 18,66 px kalın) | 3:1 | 1.4.3 |
| Arayüz bileşenleri ve anlamlı grafikler (alan kenarı, ikon, odak göstergesi) | 3:1 | 1.4.11 |
Bileşen durumları: tasarımda en çok unutulan kısım
Tasarım dosyalarında bileşenler çoğunlukla tek hâliyle çizilir; gerçek arayüzde ise her bileşenin birden fazla durumu vardır. Bir düğme ya da form alanı için en az şu durumları tasarlayın:| Durum | Ne göstermeli |
|---|---|
| Varsayılan | Tıklanabilir olduğunu biçimiyle belli eder |
| Üzerine gelme (hover) | Hafif renk ya da gölge değişimi; dokunmatik ekranda yoktur, bu yüzden tek başına bilgi taşımamalı |
| Klavye odağı (focus) | Belirgin bir odak halkası, çevresine karşı en az 3:1 kontrast |
| Basılı (active) | Tıklamanın algılandığını hissettirir |
| Devre dışı (disabled) | Neden devre dışı olduğu yakınında açıklanır |
| Yükleniyor | İkinci tıklamayı engeller, düğmenin genişliği değişmez |
| Hata ve başarı | Metinle açıklanır, yalnızca renkle değil |
| Boş durum (empty state) | Liste boşsa ne yapılacağını söyler |
- Odak halkasını kaldırmayın: :focus-visible kullanın; tarayıcı halkayı klavyeyle gezinirken gösterir, fareyle bir düğmeye tıklandığında göstermez.
- Odak örtülmesin: WCAG 2.2 ile gelen 2.4.11 ölçütü (AA), odaklanan öğenin yapışkan başlık ya da çerez bandı gibi öğelerin altında tamamen kaybolmamasını ister. scroll-padding-top değerini başlığın gerçek yüksekliğine eşitlemek, W3C'nin bu ölçüt için listelediği yeterli tekniklerden biridir (C43).
- Hedef en az 24×24: 2.5.8 ölçütü (AA), işaretçiyle (fare, dokunma) kullanılan hedeflerin en az 24×24 CSS piksel olmasını ya da yeterli aralıkla yerleştirilmesini şart koşar; cümle içindeki bağlantılar gibi birkaç istisnası vardır.
- Dokunmatikte daha büyük: Apple, iOS ve iPadOS'ta 44×44 pt, Material Design ise 48×48 dp önerir; örnekteki 44 piksellik alt sınır AAA düzeyindeki 2.5.5 ölçütünü de karşılar.
Code:
.btn:focus-visible {
outline: 3px solid var(--color-focus);
outline-offset: 2px;
}
html { scroll-padding-top: 80px; } /* yapışkan başlık odaklanan öğeyi örtmesin */
.btn { min-height: 44px; min-width: 44px; }
@media (prefers-reduced-motion: reduce) {
*, *::before, *::after {
animation-duration: 0.01ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0.01ms !important;
scroll-behavior: auto !important;
}
}
Formlar: dönüşümün kazanıldığı ya da kaybedildiği yer
- Etiket her zaman görünür: Yer tutucu (placeholder) etiket değildir; yazmaya başlayınca kaybolur ve çoğu tasarımda soluk bir renkte bırakılır. Etiketi alanın üstüne koyun.
- Doğru klavye ve otomatik doldurma: type="email", type="tel" ve inputmode="numeric" mobilde doğru klavyeyi açar; autocomplete="email", "tel", "postal-code", "one-time-code" gibi değerler tarayıcının alanları doldurmasını sağlar. Kullanıcının kendi bilgilerini isteyen alanlarda bu amacın kodda belirtilmesi WCAG 1.3.5 ölçütünün (AA) de gereğidir.
- Aynı bilgiyi iki kez istemeyin: 3.3.7 ölçütü (A), aynı süreçte daha önce girilmiş bir bilgi yeniden gerekiyorsa bunun otomatik doldurulmasını ya da seçilebilir olmasını ister; "fatura adresi teslimat adresiyle aynı" seçeneği tipik bir örnektir.
- Hata mesajı sorunu ve çözümü söyler: "Geçersiz giriş" yerine "Telefon numarası 10 haneli olmalı, ör. 5XX XXX XX XX" yazın; WCAG 3.3.3 (AA) de düzeltme önerisi biliniyorsa kullanıcıya sunulmasını ister. Doğrulamayı kullanıcı alandan çıkınca yapın, her tuş vuruşunda değil; gönderimde ilk hatalı alana odaklanın.
- Türkiye'ye özgü alanlar: T.C. kimlik numarası 11 hanedir ve yalnızca yasal ya da operasyonel bir gerekçe varsa istenmelidir; KVKK'nın "işlendikleri amaçla bağlantılı, sınırlı ve ölçülü olma" ilkesi de bunu gerektirir. Adres formlarında il ve ilçeyi listeden seçtirmek, serbest metne göre genellikle daha az hata üretir. İsim ve adres alanlarında Türkçe karakterleri kabul edin; arama ve eşleştirmede "I/ı" ve "İ/i" dönüşümlerini Türkçe kurallarla yapın.
- Giriş ekranı: 3.3.8 ölçütü (AA), girişin hiçbir adımında parola hatırlama ya da bulmaca çözme gibi bir bilişsel testin zorunlu tutulmamasını ister; alternatif bir yöntem ya da kullanıcıya yardım eden bir mekanizma sunuluyorsa test kalabilir. Nesne tanımaya dayalı testler (ör. görsellerden bisikletleri seçtirmek) bu düzeyde ayrıca istisnadır. Parola alanında yardımcı mekanizma parola yöneticisi ve yapıştırmadır; ikisini de engellemeyin.
Duyarlı düzen: cihaz değil, içerik belirler
Kırılma noktalarını (breakpoint) cihaz modellerine göre değil, içeriğin bozulduğu genişliğe göre seçin; 480, 768, 1024 ve 1280 piksel civarı pratik bir başlangıçtır. Bileşen düzeyinde kapsayıcı sorguları (container queries), bir kartın sayfanın değil, içinde durduğu alanın genişliğine göre düzen değiştirmesini sağlar; Chrome, Edge, Firefox ve Safari'nin güncel sürümleri bunu destekler. WCAG 1.4.10 (Reflow, AA), içeriğin 320 CSS piksel genişlikte iki yönlü kaydırma gerektirmeden kullanılabilmesini ister; bu, 1280 piksel genişliğindeki bir masaüstü penceresinde %400 yakınlaştırmaya karşılık gelir. Veri tabloları gibi iki boyutlu düzen gerektiren içerik bu kuralın dışındadır: yatay kaydırılan bir tablo kapsayıcısı kabul edilebilir, ama sayfanın tamamı yatay kaymamalıdır.
Code:
.cards { container-type: inline-size; }
@container (min-width: 600px) {
.card { display: grid; grid-template-columns: 200px 1fr; gap: var(--space-5); }
}
Performans da bir tasarım kararıdır
Core Web Vitals ölçümleri doğrudan tasarım kararlarından etkilenir. "İyi" sınırları: Largest Contentful Paint (LCP) için 2,5 saniye, Interaction to Next Paint (INP; Mart 2024'te FID'nin yerini aldı) için 200 milisaniye, Cumulative Layout Shift (CLS) için 0,1. Google bu değerlerin sayfa yüklemelerinin 75. yüzdelik diliminde, mobil ve masaüstü için ayrı ayrı ölçülmesini önerir. CLS'yi üç alışkanlık düşürür: görsellere width ve height (ya da aspect-ratio) vermek, geç yüklenen reklam ve duyuru alanlarına önceden yer ayırmak, çerez bandını içeriği aşağı iten bir blok yerine sabit konumlu bir katman olarak göstermek. Böyle bir katmanın odaklanan öğeyi örtmemesine de dikkat edin. Açılış görselinin arka plan videosu ya da ağır bir slayt yerine optimize edilmiş tek bir görsel olması çoğu zaman LCP'yi iyileştirir.Sık yapılan hatalar ve çözümleri
| Belirti | Neden | Çözüm |
|---|---|---|
| Açık gri yardımcı metin zor okunuyor | #999999 beyaz zeminde 2,85:1; eşik 4,5:1 | #767676 (4,54:1) ya da daha koyu bir ton; düzeltmeyi token'da yapın |
| Form alanı zeminden ayırt edilmiyor | #CCCCCC kenar beyaz zeminde 1,61:1 | Kenar alanı gösteren tek işaretse en az 3:1, ör. #8A8A8A (3,45:1) |
| Klavyeyle gezinirken odak görünmüyor | Halka outline: none ile kaldırılmış | :focus-visible ile belirgin bir halka tanımlayın |
| Tab tuşuyla ilerlerken odaklanan öğe başlığın altında kalıyor | Kaydırma, yapışkan başlığın yüksekliğini hesaba katmıyor | scroll-padding-top değerini başlık yüksekliğine eşitleyin |
| Sayfa yüklenirken içerik zıplıyor | Görsel ya da reklam alanının boyutu tanımsız | width/height ya da aspect-ratio ile yer ayırın |
| Yakınlaştırınca başlıklar büyümüyor | Yazı boyutu yalnızca vw ile verilmiş | clamp() içinde rem ile vw'yi birlikte kullanın |
| Büyük harfli menüde "ISTANBUL" görünüyor | Sayfa lang="tr" bildirmiyor | html etiketine lang="tr" ekleyin |
Yayından önce tasarım kontrol listesi
- Tüm metin ve arka plan çiftleri kontrast eşiklerini geçiyor mu, açık ve karanlık modda?
- Sayfa yalnızca klavyeyle baştan sona kullanılabiliyor mu, odak her zaman görünür mü?
- %200 yakınlaştırmada ve 320 piksel genişlikte içerik kayboluyor mu?
- Her bileşenin yükleniyor, hata, boş ve devre dışı durumları tasarlandı mı?
- Form hataları metinle açıklanıyor ve ilk hatalı alana odaklanılıyor mu?
- Boşluklar ve yazı boyutları ölçekten mi seçildi, yoksa keyfî değerler var mı?
- Uzun Türkçe kelimeler ve çeviriler düğmelerden ve menülerden taşıyor mu?
- Görsellerin boyutu tanımlı mı, sayfa yüklenirken düzen kayıyor mu?
Sık sorulan sorular
UI ile UX arasındaki fark nedir?UX (kullanıcı deneyimi), kullanıcının amacına nasıl ulaştığını kapsar: akış, bilgi mimarisi, araştırma. UI (kullanıcı arayüzü) bu akışın ekrandaki somut hâlidir: düzen, tipografi, renk, bileşenler. İyi bir UI kötü bir akışı kurtaramaz; iyi bir akış da okunamayan bir arayüzde kaybolur.
Hangi kırılma noktalarını kullanmalıyım?
İçeriğinizin bozulduğu genişlikleri. 480, 768, 1024 ve 1280 piksel civarıyla başlayın; ardından gerçek sayfaları tarayıcıda daraltıp genişletin, satırların aşırı uzadığı ya da öğelerin sıkıştığı genişliklere kırılma noktası koyun. Stilleri mobil öncelikli, min-width sorgularıyla yazmak kuralların birbirini ezmesini azaltır.
Erişilebilirlik yasal bir zorunluluk mu?
Pazarınıza ve sektörünüze bağlıdır. Örneğin AB'deki tüketicilere sunulan e-ticaret hizmetleri için Avrupa Erişilebilirlik Yasası (European Accessibility Act, 2019/882 sayılı AB Direktifi) 28 Haziran 2025'ten beri uygulanıyor; hizmet sunan mikro işletmeler bu yükümlülüklerden muaftır. Yasal zorunluluk olmasa da erişilebilir arayüz herkes için daha kullanışlıdır; kendi durumunuz için hukuki görüş alın.
Tasarımı Figma'da mı yapmalıyım, doğrudan kodda mı?
Keşif ve karşılaştırma için tasarım aracı hızlıdır; durumlar, gerçek içerik ve duyarlı davranış ise ancak kodda sınanır. Token'ları iki tarafta aynı adlarla tutmak aradaki kaybı azaltır.
Karanlık mod gerekli mi?
Zorunlu değil. Ama işletim sisteminde karanlık temayı seçen kullanıcıların tercihine prefers-color-scheme medya sorgusuyla uymak, token'larla kurulmuş bir palette kolaydır; karanlık mod yalnızca ikinci bir değer setidir. Kontrastı iki modda da ölçün.
Sonuç ve sonraki adımlar
Tutarlı bir arayüz, her kararın bir kez sayı olarak verilip her yerde aynı biçimde uygulanmasından doğar. Başlamak için:- Boşluk, tipografi ve renk değerlerini token olarak tanımlayın; tasarım aracında ve kodda aynı adları kullanın.
- Mevcut paletinizdeki tüm metin/zemin çiftlerinin kontrastını ölçün.
- En çok kullanılan beş bileşen için tüm durumları tasarlayıp belgeleyin.
- En önemli formunuzu (kayıt, ödeme, iletişim) yukarıdaki form kurallarıyla gözden geçirin.
- Kontrol listesini her sürümden önce çalıştırın.
Who this guide is for
Web interface (UI) design is as much about how a page is used as about how it looks: which element is read first, how people can tell a button is clickable, what a form says when something goes wrong. This guide collects concrete rules that designers and front-end developers can share as a common language: a grid and spacing system, a type scale, colour and contrast, component states, forms, responsive layout, common mistakes and a design check before release. Most of the rules are expressed as numbers, so the conversation becomes "raise the gap from 16 to 24 pixels" rather than "make it feel a bit more airy".Keeping these rules alive across teams is the subject of our articles on design systems and the Figma-to-code design handoff.
Grid and spacing system
Interfaces look orderly when every measurement comes from a small scale. The usual approach is a base unit of 4 or 8 pixels: gaps are picked from values such as 4, 8, 12, 16, 24, 32, 48 and 64, and no arbitrary 13 or 22 pixels creep in.- Container: on text-heavy pages the content width is capped for readability; tables and dashboards can use a wider container. Gutters grow with the breakpoint, for example 16 pixels on mobile, 24 on tablets and 32 on desktop.
- Column grid: 12 columns on desktop, 8 on tablets and 4 on mobile is a common starting point. The grid is an alignment tool rather than a cage; what matters is that every block on the page sits on the same left and right lines.
- Proximity: the gap between related elements should be clearly smaller than the gap between unrelated groups, for example 4-8 pixels between a label and its field and 24-32 pixels between form groups.
Code:
:root {
--space-1: 4px; --space-2: 8px; --space-3: 12px; --space-4: 16px;
--space-5: 24px; --space-6: 32px; --space-7: 48px; --space-8: 64px;
--gutter: var(--space-4);
}
@media (min-width: 768px) { :root { --gutter: var(--space-5); } }
@media (min-width: 1200px) { :root { --gutter: var(--space-6); } }
.container {
max-width: 1200px;
margin-inline: auto;
padding-inline: var(--gutter);
}
Typography: scale, line length, fluid sizes
Text makes up most of an interface, and a few rules improve readability noticeably:- Body text: 16 pixels, the browser default, is the widely accepted minimum; 17-18 pixels is more comfortable for long reading. Keep line height between 1.4 and 1.6 for body text and between 1.1 and 1.3 for headings.
- Line length: the common recommendation is 45-75 characters per line. A limit such as max-width: 70ch in CSS makes this easy.
- Scale: heading sizes grow by a fixed ratio (for example 1.2 or 1.25). Three or four levels are enough for most sites, rather than six different heading sizes.
- Fluid type: use clamp() to let headings grow with the viewport. Sizes set only in vw units do not grow with browser zoom; W3C lists this as a failure (F94) of criterion 1.4.4, which requires text to be resizable up to 200%. Combine rem with vw instead.
Code:
body { font-size: 1rem; line-height: 1.5; }
h1 { font-size: clamp(1.75rem, 1.2rem + 2.2vw, 2.75rem); line-height: 1.15; }
h2 { font-size: clamp(1.375rem, 1.1rem + 1.1vw, 1.875rem); line-height: 1.2; }
.prose { max-width: 70ch; }
Colour and contrast: the WCAG 2.2 thresholds
WCAG 2.2 became a W3C Recommendation on 5 October 2023; the current text on w3.org is dated 12 December 2024. At level AA, which most organisations aim for, the contrast thresholds are:| Element | Minimum contrast | Criterion |
|---|---|---|
| Normal text | 4.5:1 | 1.4.3 |
| Large text (18 point, or 14 point bold; roughly 24 px or 18.66 px bold) | 3:1 | 1.4.3 |
| UI components and meaningful graphics (field borders, icons, focus indicators) | 3:1 | 1.4.11 |
Component states: the most forgotten part of design
Design files often show a component in a single state, while in the real interface every component has several. For a button or a form field, design at least these:| State | What it should show |
|---|---|
| Default | Its shape makes clear it can be clicked |
| Hover | A subtle colour or shadow change; it does not exist on touch screens, so it must not carry information on its own |
| Keyboard focus | A clear focus ring with at least 3:1 contrast against its surroundings |
| Active (pressed) | Confirms the click registered |
| Disabled | Explains nearby why it is disabled |
| Loading | Prevents a second click without changing the button's width |
| Error and success | Explained in text, not by colour alone |
| Empty state | Tells people what to do when a list is empty |
- Keep the focus ring: use :focus-visible, which lets the browser show the ring during keyboard navigation but not when a button is clicked with a mouse.
- Do not hide focus: criterion 2.4.11 (AA), new in WCAG 2.2, requires that a focused element is not entirely hidden under sticky headers or cookie banners. Setting scroll-padding-top to the header's real height is one of the sufficient techniques W3C lists for it (C43).
- Targets of at least 24 by 24: criterion 2.5.8 (AA) requires pointer targets to be at least 24 by 24 CSS pixels or spaced well enough apart, with a few exceptions such as links inside a sentence.
- Larger for touch: Apple recommends 44 by 44 points on iOS and iPadOS, Material Design 48 by 48 dp; the 44-pixel minimum in the example also meets the AAA criterion 2.5.5.
Code:
.btn:focus-visible {
outline: 3px solid var(--color-focus);
outline-offset: 2px;
}
html { scroll-padding-top: 80px; } /* keep the sticky header off the focused element */
.btn { min-height: 44px; min-width: 44px; }
@media (prefers-reduced-motion: reduce) {
*, *::before, *::after {
animation-duration: 0.01ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0.01ms !important;
scroll-behavior: auto !important;
}
}
Forms: where conversions are won or lost
- Labels are always visible: a placeholder is not a label; it disappears as soon as people type and is usually styled in a faint colour. Put the label above the field.
- The right keyboard and autofill: type="email", type="tel" and inputmode="numeric" open the right keyboard on mobile; autocomplete values such as "email", "tel", "postal-code" and "one-time-code" let the browser fill fields in. For fields that collect information about the user, declaring that purpose in the markup is also what WCAG 1.3.5 (AA) requires.
- Do not ask for the same thing twice: criterion 3.3.7 (A) asks that information already entered in the same process, when it is needed again, is filled in automatically or offered for selection; a "billing address same as delivery" option is the typical example.
- Error messages state the problem and the fix: instead of "Invalid input", write something like "The phone number must have 10 digits, e.g. 5XX XXX XX XX" (a Turkish mobile number); WCAG 3.3.3 (AA) also asks for a correction suggestion whenever one is known. Validate when the user leaves a field rather than on every keystroke, and on submit move focus to the first invalid field.
- Fields specific to Türkiye: the Turkish national ID number (T.C. kimlik no) has 11 digits and should only be requested when there is a legal or operational reason; the principle in KVKK, Türkiye's Personal Data Protection Law No. 6698, that data must be "relevant, limited and proportionate" to the purpose points the same way. In address forms, choosing the province (il) and district (ilçe) from lists usually produces fewer errors than free text. Accept Turkish characters in names and addresses, and apply Turkish rules to I/ı and İ/i when searching and matching.
- Login screens: criterion 3.3.8 (AA) says no step of a login may require a cognitive function test, such as remembering a password or solving a puzzle, unless an alternative method or a mechanism that helps the user is available. Tests based on recognising objects (picking the bicycles from a set of images, say) are also exempt at this level. For passwords, the helping mechanism is a password manager or pasting, so do not block either.
Responsive layout: content decides, not devices
Choose breakpoints where your content breaks, not by device model; around 480, 768, 1024 and 1280 pixels is a practical start. At component level, container queries let a card change its layout according to the width of the space it sits in rather than the width of the page; current versions of Chrome, Edge, Firefox and Safari support them. WCAG 1.4.10 (Reflow, AA) requires content to be usable at a width of 320 CSS pixels without scrolling in two directions, which equals 400% zoom in a desktop window 1280 pixels wide. Content that needs a two-dimensional layout, such as data tables, is exempt: a horizontally scrolling table container is acceptable, but the page as a whole must not scroll sideways.
Code:
.cards { container-type: inline-size; }
@container (min-width: 600px) {
.card { display: grid; grid-template-columns: 200px 1fr; gap: var(--space-5); }
}
Performance is a design decision too
Design choices feed straight into the Core Web Vitals. The "good" thresholds are 2.5 seconds for Largest Contentful Paint (LCP), 200 milliseconds for Interaction to Next Paint (INP, which replaced FID in March 2024) and 0.1 for Cumulative Layout Shift (CLS); Google recommends measuring them at the 75th percentile of page loads, separately for mobile and desktop. Three habits lower CLS: giving images width and height (or aspect-ratio), reserving space for late-loading ads and announcements, and showing the cookie notice as a fixed overlay rather than as a block that pushes content down. Just make sure such an overlay does not cover the focused element. A single optimised hero image instead of a background video or a heavy slider usually improves LCP.Common mistakes and how to fix them
| Symptom | Cause | Fix |
|---|---|---|
| Light grey helper text is hard to read | #999999 on white is 2.85:1; the threshold is 4.5:1 | #767676 (4.54:1) or darker; fix it in the token |
| Form fields blend into the background | A #CCCCCC border on white is 1.61:1 | If the border is the only cue, at least 3:1, e.g. #8A8A8A (3.45:1) |
| Focus is invisible during keyboard navigation | The ring was removed with outline: none | Define a clear ring with :focus-visible |
| Tabbing puts the focused element under the header | Scrolling ignores the sticky header's height | Set scroll-padding-top to the header height |
| Content jumps while the page loads | Images or ad slots have no defined size | Reserve space with width/height or aspect-ratio |
| Headings do not grow when zooming | Font size set in vw only | Combine rem with vw inside clamp() |
| An uppercase menu shows "ISTANBUL" | The page does not declare lang="tr" | Add lang="tr" to the html element |
Design checklist before release
- Do all text and background pairs pass the contrast thresholds, in both light and dark mode?
- Can the page be used end to end with the keyboard alone, and is focus always visible?
- Does any content disappear at 200% zoom or at a width of 320 pixels?
- Have the loading, error, empty and disabled states been designed for every component?
- Are form errors explained in text, and does focus move to the first invalid field?
- Are gaps and font sizes taken from the scale, or have arbitrary values crept in?
- Do long Turkish words and translations overflow buttons and menus?
- Do images have defined dimensions, or does the layout shift while the page loads?
Frequently asked questions
What is the difference between UI and UX?UX (user experience) covers how people reach their goal: the flow, the information architecture, the research. UI (user interface) is the concrete form of that flow on screen: layout, typography, colour, components. Good UI cannot rescue a bad flow, and a good flow gets lost in an unreadable interface.
Which breakpoints should I use?
The widths where your content breaks. Start around 480, 768, 1024 and 1280 pixels, then narrow and widen real pages in the browser and add a breakpoint wherever lines get too long or elements get cramped. Writing styles mobile first with min-width queries keeps rules from overriding each other.
Is accessibility a legal requirement?
It depends on your market and sector. For example, the European Accessibility Act (EU Directive 2019/882) has applied since 28 June 2025 to e-commerce services offered to consumers in the EU; microenterprises providing services are exempt. Even without a legal duty, an accessible interface is easier for everyone to use; get legal advice for your own situation.
Should I design in Figma or directly in code?
A design tool is fast for exploring and comparing options; states, real content and responsive behaviour can only be tested in code. Keeping tokens under the same names on both sides reduces what gets lost in between.
Do I need a dark mode?
It is not mandatory. For people who choose a dark theme in their operating system, though, following that preference with the prefers-color-scheme media query is cheap when the palette is built on tokens, because dark mode is just a second set of values. Measure contrast in both modes.
Conclusion and next steps
A consistent interface comes from making each decision once, as a number, and applying it the same way everywhere. To start:- Define spacing, typography and colour values as tokens, and use the same names in the design tool and in code.
- Measure the contrast of every text/background pair in your current palette.
- Design and document every state of your five most used components.
- Review your most important form (sign-up, checkout, contact) against the form rules above.
- Run the checklist before every release.
Last edited: