Sanal düğümler, liste işareti
Pseudo-Elementler (Pseudo-Elements)
HTML kodunda fiziksel olarak "var olmayan",
ancak
CSS tarafından
"yoktan var edilen" veya bir bütünün
"belirli bir
parçasını"
hedefleyen sanal seçicilerdir.
Aşağıda pseudo-elementleri inceleyeceğiz.
CSS Pseudo-Elementler Görünmeyeni Hedeflemek: Durumlar, Etkileşimler ve Sanal Parçalar
CSS Pseudo-Element Haritası (Kullanım Alanlarına Göre) Soldan sağa tipik öğrenme / uygulama akışı; her kutu farklı renk kodu taşır
Önce kutuya sanal içerik ekleyip metni parçalarsınız; ardından üst katman ve medya; en sonda gölge köprüleri. Ok yönü önerilen okuma sırasını gösterir.
Tipografi ve seçim
Modal / fullscreen perdesi
Video / WebVTT
Slot içeriği & part API
- 1 · İçerik #34d399
- 2 · Metin #818cf8
- 3 · Üst katman #fbbf24
- 4 · Medya #f472b6
- 5 · Gölge #a78bfa
::-webkit-scrollbar* ve benzeri önekli
seçiciler standart değildir; yalnızca belirli motorlarda çalışır — haritada ayrı uyarı olarak
gösterilir.
"Pseudo" kelimesi, etimolojik olarak "sahte", "yapay" veya "taklit" anlamına gelse de; CSS dünyasında bu terim, HTML kodunda fiziksel olarak var olmayan soyut kavramları somutlaştıran, tasarımın en güçlü mekanizmalarından birini ifade eder.
Standart seçiciler (Etiket, Sınıf , ID ) sayfadaki statik ve değişmez "varlıkları" hedeflerken; Pseudo seçiciler bu varlıkların zaman içindeki "durumlarını" veya geometrik "parçalarını" hedefler.
Bir web sayfası statik bir tablo değildir; yaşayan, nefes alan ve kullanıcıyla sürekli diyalog halinde olan interaktif bir ortamdır.
Pseudo yapıları, geliştiricinin HTML iskeletine dokunmadan ve ekstra JavaScript kodu yazmadan tarayıcıya mantıksal emirler vermesini sağlar.
"Kullanıcı fareyi bu kutunun üzerine getirdiğinde ne olsun?", "Listenin her üçüncü elemanı nasıl görünsün?" veya
"Bir metnin ilk harfi nasıl vurgulansın?" sorularının cevabı bu seçicilerde gizlidir.
Teknik mimaride bu kavram iki ana disipline ayrılır:
Tarihsel Dönüşüm: Tek Nokta vs Çift NoktaCSS2 döneminde hem sınıflar hem de elementler için tek nokta (:before) kullanılırdı.
Ancak CSS3 ile birlikte, "Durum" ve "Parça" kavramlarını birbirinden kesin çizgilerle ayırmak için çift nokta ( ::before ) standardı getirildi.
Tarayıcılar geriye dönük uyumluluk adına tek noktayı hala desteklese de, modern ve doğru yazım şekli çift noktadır.
Görünmez Mimari: Shadow DOM Sözde elementler, aslında tarayıcının Shadow DOM adı verilen özel katmanında oluşturulur.
Bu yüzden JavaScript ile document.querySelector('.element') dediğinizde, bu sanal parçaları seçemezsiniz, onlar, sadece CSS'in görebildiği hayaletlerdir.
HTML Kirliliğine Son Sadece görsel bir süsleme ( bir ikon, bir çizgi veya tırnak işareti ) için HTML'e boş bir <span> veya <div> eklemek, kodunuzu kirletir ve ekran okuyucuları şaşırtabilir.
Sözde elementler, bu dekoratif yükü HTML'den alıp tamamen CSS'e yıkarak içeriğinizi sunumunuzdan ayırır.
Kritik Kural: "Content" Zorunluluğu Bir sözde elementin (::before veya ::after) ekranda var olabilmesi için, CSS içinde mutlaka
content: ''; özelliğinin tanımlanması gerekir.
İçi boş bile olsa bu özellik yazılmazsa, tarayıcı o elementi oluşturmaz , bu, sözde elementlerin "Yaşam Enerjisi"dir.
Sanal Yapı Taşları Sözde Öğeler (Pseudo-Elements)
Eğer az önce incelediğimiz "Sözde Sınıflar" bir öğenin ruh halini değiştiriyorsa; "Sözde Öğeler", o öğeye yeni uzuvlar ekler, onu parçalarına ayırır veya makyaj yapar.
HTML kodlarına dokunmadan, sadece CSS kullanarak sayfaya estetik detaylar, ikonlar veya tipografik süslemeler eklemenin yegane yolu budur.
Bunlar, DOM ağacında fiziksel olarak bulunmazlar; tarayıcı onları "render" aşamasında sanal olarak yaratır.
"Hayalet" Elementlerin MantığıWeb geliştirmede "İçerik" ve "Sunum" birbirinden kesin çizgilerle ayrılmalıdır.
Bir web sayfası, veriyi taşıyan iskelet ve ona giydirilen kıyafetten oluşur.
Sözde öğeler, bu prensibi korumak için vardır.
Örneğin: Bir başlığın yanına sırf dekoratif amaçlı bir "yıldız ikonu" koymak istiyorsanız, bunu içine fiziksel bir etiket olarak eklemek ( boş bir <span> kullanmak ) kodu "kirletmek" anlamına gelir.
Çünkü o yıldızın anlamsal bir değeri yoktur, sadece süstür.
İşte sözde öğeler, kodunu tertemiz tutarken, sayfaya sanki orada ekstra bir element varmış gibi görsel eklemeler yapmanızı sağlar.
Teknik Dünyanın Perde Arkası: DOM ve Render AğacıWeb tarayıcınız bir sayfayı açtığında, saniyeler içinde arka planda karmaşık bir inşaat süreci gerçekleşir.
Bu süreci anlamak, Sözde Öğelerin neden "sözde" olduğunu ve neden dosyasında görünmedikleri halde ekranda var olduklarını anlamamızı sağlar.
Bu ilişkiyi bir "Mimar ve İç Mimar" ilişkisine benzetebiliriz.
DOM Ağacı (Belge Nesne Modeli): Mimarın ProjesiDOM, bir web sayfasının "mutlak gerçeğidir".
Yazdığınız kodlarının tarayıcı tarafından okunup, hiyerarşik bir soy ağacına dönüştürülmüş halidir.
Ne Görür: Sadece etiketlerini (div, p, span) ve bunların içindeki metinleri görür.
Görevi: Sayfanın iskeletini ve anlamsal yapısını oluşturmaktır.
Sınırı: DOM, renklerden, boyutlardan veya süslemelerden anlamaz.
O sadece "Burada bir başlık var, altında bir paragraf var" diyen teknik rapordur.
Render Ağacı (Görselleştirme): İç Mimarın EseriRender Ağacı, mimarın projesinin üzerine stil kurallarının giydirilmesiyle oluşan "son görsel üründür".
Tarayıcı, DOM'daki iskeleti alır, dosyasındaki kuralları okur ve ekrana neyin, nasıl çizileceğine karar verir.
Ne Yapar: Görünmeyen elemanları (display: none) eler ve geri kalanları boyar.
Görevi: Kullanıcının gözüne hitap eden nihai görüntüyü oluşturmaktır.
Sözde Öğelerin "Hayalet" Doğasıİşte Sözde Öğeler (::before, ::after) tam bu iki aşamanın arasındaki boşlukta, sihirli bir şekilde ortaya çıkar.
DOM'da Yokturlar: Eğer koduna bakarsanız, bu öğeleri göremezsiniz.
Çünkü veritabanından gelmezler, etiketleri arasında fiziksel bir yer kaplamazlar.
Render Aşamasında Doğarlar: Tarayıcı sayfayı boyamaya başladığı anda ( Render Ağacı oluşurken ), dosyası devreye girer ve tarayıcıya şöyle fısıldar:
"Evet, planda yok ama sen yine de şu başlığın yanına kırmızı bir kutu çiz."
Neden Çift Nokta (::) Kullanıyoruz?'in ilk yıllarında, hem durum bildiren sınıflar ( :hover ) hem de sanal öğeler ( :before ) tek nokta ile yazılıyordu.
Ancak modern standartlarda bu iki kavramı birbirinden ayırmak için önemli bir söz dizimi kuralı getirildi:
Tek Nokta (:): Bir durumu veya mantıksal sırayı ifade eder.
Çift Nokta (::): Geometrik bir parçayı veya sanal bir nesneyi ifade eder.
Bu ayrım, geliştiricinin koda baktığında "Burada bir olay mı var, yoksa bir parça mı var?" sorusunu saniyeler içinde yanıtlamasını sağlar.
Tasarımın "Görünmez" İşçileriSözde öğeler, modern web tasarımının "makyaj sanatçılarıdır".
Bir alıntının başına konan devasa tırnak işaretlerinden, maddeli listelerin özel ikonlarına, fotoğrafların üzerindeki renkli filtrelerden, karmaşık sayfa düzenlerini ayakta tutan görünmez duvarlara kadar her yerde onlar çalışır.
Kullanıcıya zengin bir görsellik sunarken, arama motorlarının ve ekran okuyucuların taradığı saf metnini sade ve anlaşılır bırakırlar.
DOM’dan layout’a: üretilen pseudo kutular ::before / ::after — DOM çocuğu değil; tarayıcının oluşturduğu kutu (örnek şema)
Aşağıdaki şema yalnızca en sık kullanılan çifti gösterir. Bu kutular, HTML’de kardeş gibi yazılmaz; stil motoru hesaplarken ek düzen kutuları üretir — Shadow DOM’daki gölge ağaçtan farklı bir mekanizmadır.
::marker, ::first-line,
::selection, ::backdrop …) farklı hedeflerde çalışır; aynı “önce /
sonra içerik kutusu” modeli her zaman geçerli değildir.
Etiket + metin düğümleri; ::before burada
yoktur.
Üstten alta boyama / hit-test sırası için tipik düzen.
::before ve ::after kutuları,
padding sınırı içinde — gerçek içeriğin biçimlendirilmiş kutusunda — ve çoğu
yerde metinle birlikte içerik alanı akışında önce ve sonra sıralanır.
Margin ve border çizgisi bu üretilen kutuların dışında kalır; onlar öğenin kendi
margin/border’ıdır.
querySelector
ile seçilmezler. Görsel olarak “yanında duran kutu” gibi düşünün, çocuk ilişkisi gibi
değil.
Tasarımın Yaratıcı İkizleri ve Sanal Katmanlar :before ve ::after:
CSS dünyasının en çok kullanılan, en çok yönlü ve tasarımcının "İsviçre Çakısı" olarak nitelendirilen araçları bu ikisidir.
İsimleri dilimize "önce" ve "sonra" olarak çevrilse de, bu kelimeler zamansal bir sırayı değil, mekansal bir konumu ifade eder.
Onlar, bir HTML öğesine kod yazmadan eklenen sanal uzantılar ve görsel protezlerdir.
Bir web sayfasını inşa ederken bazen elinizdeki HTML etiketleri ( div, p, span ) tasarım hayallerinizi gerçekleştirmek için yetersiz kalır.
İşte bu noktada ::before ve ::after devreye girer.
Bu yapılar, mevcut bir etiketinin içine sızarak, o etiketin başlangıç ve bitiş noktalarında "sanal birer gayrimenkul" yaratırlar.
Bu alanlar, dosyanızın kaynak kodunda asla yer almazlar.
Veritabanında kayıtlı değillerdir ve kopyala-yapıştır yapılamazlar.
Onlar tamamen tarayıcının "boyama" aşamasında, tarafından yaratılan görsel illüzyonlardır.
Bu özellikleri sayesinde, sayfanın bilgi taşıyan iskeletine dokunmadan, sayfayı bir ressam gibi süslemenize, ikonlarla donatmanıza veya karmaşık geometrik şekiller eklemenize olanak tanırlar.
Kısacası; eğer bir evin tuğlaları ve duvarlarıysa, ::before ve ::after o evin duvar kağıdı, tabloları ve dekoratif aydınlatmalarıdır.
Evin yapısında ( mimarisinde ) görünmezler ama evin atmosferini tamamen değiştirirler.
Altın Kural: "content" Olmazsa OlmazBu sanal elementlerin çalışması için content özelliği bir "kontağı çevirme" anahtarıdır.
CSS bloğunuzda diğer her şeyi ( genişlik, renk, pozisyon ) mükemmel yazsanız bile, eğer content: '';
( içi boş bile olsa ) satırını yazmazsanız, tarayıcı bu elementi oluşturmayı reddeder.
Konumlandırma Paradoksu: İçeride mi, Dışarıda mı? İsimleri "Önce" ve "Sonra" olduğu için, çoğu geliştirici bu elementlerin hedeflenen kutunun dışına yerleştiğini sanır fakat bu bir kritik bir yanılgıdır.
::before, etiketin açılış tag'inden hemen sonra; ::after ise kapanış tag'inden hemen önce yerleşir.
Yani teknik olarak her ikisi de, hedeflediğiniz elementin çocuklarıdır ve ebeveynin sınırları içinde yaşarlar.
Varsayılan Davranış: "Inline" Tuzağı Bu elementler yaratıldığında, varsayılan olarak display: inline; özelliğine sahiptir.
Bu yüzden, onlara genişlik (width) veya yükseklik (height) verseniz bile tepki vermezler.
Onları birer kutu gibi şekillendirmek için mutlaka display: block; veya display: inline-block; tanımını yapmanız veya
position: absolute; ile akıştan koparmanız gerekir.
Sanal Konteyner Mantığı İçerideki Gizli Bölmeler
Bu öğeleri anlamanın en iyi yolu, her HTML etiketini bir kutu ( koli ) olarak hayal etmektir.
Normal şartlarda bu kutunun içinde sadece sizin yazdığınız metin veya resimler vardır. ::before ve ::after ise, bu kutunun içine, mevcut içeriğe dokunmadan yerleştirilen ekstra, görünmez bölmelerdir.
Teknik olarak bu sanal öğeler, ana elementin çocukları ( children ) gibi davranırlar.
Ancak bunlar "üvey evlat" gibidir; HTML ailesinde görünmezler, sadece CSS ailesi tarafından tanınırlar.
"Inline" (Satır İçi) DoğasıBu sanal kutular yaratıldıkları ilk anda, sanki birer harf veya kelimeymiş gibi davranırlar bu aslında şu demektir:
Teknik tabirle display: inline özelliğine sahiptirler.
Yani, bir <div> içine ::before ile kırmızı bir kutu eklerseniz, bu kutu metnin üstüne çıkmaz; metnin hemen solunda, metinle aynı satırda durur.
Eğer onlara bir boyut (genişlik/yükseklik) vermek veya onları ana elementten bağımsız hareket ettirmek isterseniz, onlara ayrıca "Sen artık bir bloksun" (display: block) demeniz gerekir.
|
Aşama
|
Açıklama
|
|---|---|
|
Ana Elementin Başlangıcı (Start Tag)
|
Tarayıcının elementi oluşturmaya
başladığı, sanal kutunun kapağının teknik
olarak açıldığı ilk andır.
|
|
::before (Sanal Öncü)
|
Henüz HTML içindeki gerçek metin veya
görsel ekrana basılmadan önce, içeriğin
en
başına sanal olarak enjekte edilen ilk parçadır.
|
|
Asıl İçerik (Actual Content)
|
HTML etiketleri arasına yazdığınız, veritabanından veya koddan gelen gerçek metinlerin/görsellerin yerleştiği merkez alandır. |
|
::after (Sanal Artçı)
|
Asıl içerik bittiği anda, ancak
kapanış etiketi gelmeden hemen önce devreye
giren son parçadır.
|
|
Ana Elementin Bitişi (End Tag)
|
Elementin sınırlarının çizildiği, kutunun kapağının kapandığı ve CSS şekillendirmesinin son bulduğu sınırdır. |
"Content" Kuralı Dijital Varoluşun Anahtarı
Web tarayıcılarının çalışma prensibinde, bir öğenin ekrana çizilebilmesi için fiziksel bir varlığa veya bir veriye sahip olması gerekir.
Sözde öğeler (::before ve ::after) HTML kodunda doğuştan yer almadıkları için, tarayıcıya onların var olduğunu kanıtlamak zorundasınız.
İşte content özelliği, bu kanıtın ta kendisidir.
Bu kuralı, sözde öğenin "yaşam sinyali" olarak düşünebilirsiniz.
Siz CSS dosyanızda bir öğeye ne kadar genişlik, yükseklik, arka plan rengi veya gölge verirseniz verin; eğer content satırını yazmazsanız, tarayıcı bu tanımlamaların hepsini "sahipsiz mektup" gibi görür ve çöpe atar.
Tarayıcı motoru, sözde öğeyi oluşturmadan önce ilk olarak bu satırı kontrol eder: "İçerik var mı? Yok. O zaman bu öğeyi oluşturma."
Boş İçerik ile Görsel Kutu Üretimi
En yaygın kullanım olan content: ""; ( içi boş çift tırnak ), teknik olarak "boş bir karakter dizisi" anlamına gelir.
Bu, tarayıcıya şu mesajı verir: "Buraya bir kutu koy, içinde metin olmayacak ama kutunun kendisi var olacak."
Bu sayede, içi metinle dolu olmayan ama görsel olarak şekillendirilebilen (kare , daire , çizgi gibi) dekoratif objeler yaratabilirsiniz.
Unutmayın; içeriği olmayan bir şeyin, görüntüsü de olamaz.""
Bu yüzden content özelliği, tasarımın başladığı sıfır noktasıdır.
HTML Kirliliğini Önleme Semantik Bütünlük
Web geliştirmede "Temiz Kod" sadece kodun güzel görünmesi değil, işlevlerin doğru katmanlara ayrılması demektir.
Bir web sayfasının ne olduğuyla (başlık, paragraf, liste) ilgilenirken; CSS, onun nasıl göründüğüyle ilgilenir.
Bu iki disiplinin birbirine karışması, projenin sürdürülebilirliğini ve kalitesini düşüren "yapısal kirliliğe" yol açar.
Eski web geliştirme alışkanlıklarında, bir başlığın altına dekoratif bir çizgi çekmek veya bir kutunun köşesine süsleme amaçlı bir ikon koymak için HTML kodunun içine içi boş <div> veya <span> etiketleri eklenirdi.
Bu yöntem, HTML dosyasını anlamsız etiketlerle şişirir ve kodun okunabilirliğini, bir kitabın sayfalarına rastgele harfler serpiştirilmiş gibi bozar.
Dekoratif İçeriğin CSS'e Taşınması (::before / ::after)::before ve ::after sözde öğeleri, bu soruna kesin bir çözüm getirir.
Dekoratif unsurları HTML yapısından tamamen soyutlayarak, onları ait oldukları yere, yani CSS katmanına taşır.
Bu sayede, HTML kodunuz sadece saf veriyi ve içeriği barındıran "semantik" bir yapı olarak kalır.
Sayfanızı tarayan Google botları veya görme engelli kullanıcılar için çalışan ekran okuyucular, CSS ile oluşturulan bu sanal süslemeleri görmezden gelir ve doğrudan içeriğin kendisine odaklanır.
Bu, tasarım ne kadar süslü olursa olsun, bilgi hiyerarşisinin ve erişilebilirliğin zarar görmemesini sağlar.
Kullanım Senaryoları Tasarımın Gizli Kahramanları
Sözde öğeler, modern web tasarımında sadece teknik bir gereklilik değil, yaratıcılığın önündeki engelleri kaldıran birer araçtır.
Bir arayüzü "düz bir belge" görünümünden kurtarıp, ona karakter ve derinlik katan dokunuşlar genellikle bu ikili sayesinde yapılır.
İnsan beyni görselleri metinlerden çok daha hızlı işler.
Bu yüzden bir "İletişim" butonunun yanında telefon ahizesi görmek veya harici bir linkin sonunda küçük bir ok işareti bulunması,
kullanıcı deneyimini hızlandırır.
::before ve ::after, bu ikonları doğrudan metnin bir parçasıymış gibi konumlandırmanızı sağlar.
HTML içine fazladan <img> veya <i> etiketleri gömmek yerine, ikonu CSS üzerinden çağırarak kodunuzu temiz tutarsınız.
İkon, metinle birlikte büyür, küçülür ve renk değiştirir; yani metinle tam bir biyolojik uyum içinde hareket eder.
Dekoratif Atmosfer ve GeometriWeb sayfalarına derinlik katmak için kullanılan arka plan şekilleri, başlıkların altındaki zarif çizgiler veya kartların üzerindeki renkli şeritler...
Bunların çoğu aslında birer ::before veya ::after eseridir.
Örneğin: Bir bölümün ( section ) arkasında duran flu, soyut bir daireyi HTML'e "boş bir kutu" olarak eklemek yerine, sözde öğe olarak yaratırsınız.
Bu sayede sayfanın anlamsal yapısını bozmadan, sadece görsel bir atmosfer yaratmış olursunuz.
Tasarımcıların "süsleme" amacıyla yaptığı hemen her şey, bu sanal katmanlara emanet edilir.
Tipografik Zenginlik: Tırnak İşaretleriDergi ve kitap tasarımından gelen o klasik estetik; yani alıntı yapılan bir paragrafın ( <blockquote> ) başında ve sonunda duran devasa, şık tırnak işaretleri...
Bu işaretler aslında metnin kendisine ait karakterler değildir; onlar birer "çerçeve" elemanıdır.
Eğer bunları klavyeden yazarsanız, kullanıcı metni kopyaladığında bu işaretler de kopyalanır ve veri kirliliği oluşur.
Ancak ::before ve ::after ile eklendiklerinde, sadece görsel bir aksesuar olarak kalırlar; metni okumayı keyifli hale getirirler ancak veriye müdahale etmezler.
<!DOCTYPE html>
<html lang="tr">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Modern Tooltip - ::before</title>
<link rel="stylesheet" href="style.css?v=1.0.150">
</head>
<body>
<div class="container">
<h2 class="title">
Modern Tooltip <span>::before</span>
</h2>
<button class="info-btn" data-tooltip="Bu işlem geri alınamaz.">
Hover Me
</button>
</div>
</body>
</html>
*,
*::before,
*::after {
box-sizing: border-box;
}
body {
font-family: 'Inter', 'Segoe UI', sans-serif;
margin: 0;
height: 100vh;
display: flex;
justify-content: center;
align-items: center;
background: radial-gradient(circle at 20% 20%, #1e293b, #020617);
}
/* layout */
.container {
text-align: center;
}
/* 🔥 modern başlık */
.title {
font-size: 32px;
font-weight: 700;
margin-bottom: 40px;
color: #e2e8f0;
position: relative;
display: inline-block;
}
/* gradient text */
.title span {
background: linear-gradient(135deg, #6366f1, #22d3ee);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
}
/* underline accent */
.title::after {
content: "";
position: absolute;
left: 50%;
bottom: -10px;
transform: translateX(-50%);
width: 60%;
height: 3px;
background: linear-gradient(90deg, #6366f1, #22d3ee);
border-radius: 10px;
opacity: 0.7;
}
/* 🔥 buton modern */
.info-btn {
position: relative;
padding: 14px 32px;
font-size: 16px;
border: none;
border-radius: 12px;
background: rgba(99, 102, 241, 0.15);
color: #e0e7ff;
backdrop-filter: blur(10px);
border: 1px solid rgba(99, 102, 241, 0.3);
cursor: pointer;
transition: all 0.3s ease;
}
/* hover depth */
.info-btn:hover {
transform: translateY(-2px) scale(1.02);
background: rgba(99, 102, 241, 0.25);
box-shadow: 0 10px 30px rgba(99, 102, 241, 0.25);
}
/* 🔥 tooltip */
.info-btn::before {
content: attr(data-tooltip);
position: absolute;
bottom: 130%;
left: 50%;
transform: translateX(-50%) translateY(10px);
background: rgba(15, 23, 42, 0.95);
color: #cbd5f5;
padding: 10px 16px;
border-radius: 10px;
font-size: 13px;
letter-spacing: 0.3px;
white-space: nowrap;
opacity: 0;
pointer-events: none;
box-shadow: 0 15px 40px rgba(0,0,0,0.5);
backdrop-filter: blur(8px);
transition: all 0.25s ease;
}
/* ok */
.info-btn::after {
content: "";
position: absolute;
bottom: 115%;
left: 50%;
transform: translateX(-50%) translateY(10px);
border-width: 6px;
border-style: solid;
border-color: rgba(15, 23, 42, 0.95) transparent transparent transparent;
opacity: 0;
transition: all 0.25s ease;
}
/* hover */
.info-btn:hover::before,
.info-btn:hover::after {
opacity: 1;
transform: translateX(-50%) translateY(0);
}
Tipografik Başlangıç / Drop Cap ::first-letter
Orta Çağ el yazması kitaplarını veya eski masal kitaplarını hatırlayın.
"Bir varmış, bir yokmuş..." diye başlayan o ilk cümlenin "B" harfi genellikle devasa boyutta, süslü ve bazen resimlerle bezeli çizilirdi.
Grafik tasarım literatüründe buna "Drop Cap" denir.
::first-letter, bu estetik mirası modern web sayfalarına taşır.
HTML içinde o harfi ayrı bir <span> içine almaya gerek kalmadan, sadece CSS kullanarak bu sanatı icra etmenizi sağlar.
Görsel Çapa ve Okuma PsikolojisiKullanıcılar web sayfalarını kelime kelime okumazlar; önce tararlar.
Uzun bir makalede veya gri bir metin bloğunda gözün tutunacak bir dala ihtiyacı vardır.
Stilize edilmiş bir ilk harf, okuyucuya "Başlangıç noktası burası, okumaya buradan başla" diyen güçlü bir görsel çapadır.
Metnin monotonluğunu kırar ve içeriğe editöryal, profesyonel bir hava katar.
Blok Element Zorunluluğu Bu seçicinin çalışması için en önemli teknik kural şudur: ::first-letter sadece blok seviyesindeki öğelere uygulanabilir.
Yani bir paragraf ( <p> ), başlık ( <h1> ) veya bir kutu (<div>) üzerinde çalışır; ancak satır içi (<span>, <a>) öğelerde çalışmaz.
Çünkü "ilk harf" kavramı, paragrafın akışıyla ve satır yapısıyla doğrudan ilişkilidir.
Teknik Neden: Neden Kısıtlıyız?Bu kısıtlamaların temel sebebi, tarayıcıların metinleri işleme mantığıdır.
Metinler, satır kutuları denilen görünmez şeritler halinde çizilir.
Eğer ::first-letter üzerinde sayfa düzenini radikal şekilde değiştiren özelliklere ( flexbox, grid vb. ) izin verilseydi, paragrafın satır yapısı parçalanır ve metin okunamaz hale gelirdi.
Bu yüzden tarayıcılar, "Sadece harfi süsle, ama metnin akışını bozma" prensibiyle çalışır.
İçerik Değişse de Kural BozulmazBu seçicinin "sözde" olmasının güzelliği dinamikliğindedir.
Eğer içerik yönetim sisteminiz metni değiştirirse, yeni metnin ilk harfi otomatik olarak bu stili alır.
"A" harfi gider, yerine "B" harfi gelir ve tasarımınız bozulmadan "K" harfi büyür.
Bu, sürdürülebilir tasarımın harika bir örneğidir.
Kısıtlı Stil Özgürlüğü: Sınırlar İçinde YaratıcılıkBir web sayfasında ::first-letter kullanırken, kendinizi sonsuz bir tuvalde değil, kuralları belirlenmiş bir oyun alanında bulursunuz.
Tarayıcılar, metin akışını ve satır yapısını korumak adına bu sanal öğe üzerinde kullanabileceğiniz özelliklerine katı sınırlar koymuştur.
Bir div etiketine uygulayabildiğiniz her stili ( display: flex veya position: absolute gibi yerleşim kuralların ) burada kullanamazsınız.
Ancak izin verilen özellikler, tipografik bir şaheser yaratmak için fazlasıyla yeterlidir.
Tipografik Manipülasyon (Font Özellikleri)Bu alanın en güçlü silahıdır.
Sadece harfin boyutunu (font-size) büyütmekle kalmaz, onun karakterini de değiştirebilirsiniz.
Örneğin, metniniz modern ve düz bir yazı tipiyle (Sans-Serif) yazılmışsa, sadece ilk harfi tırnaklı ve klasik bir fonta
( font-family: Serif ) dönüştürerek harika bir kontrast yakalayabilirsiniz.
Ayrıca harfi kalınlaştırarak (font-weight) veya italik yaparak (font-style) görsel ağırlığını artırabilirsiniz.
Görsel Ağırlık ve Kontrast (Renk ve Arka Plan)İlk harfi metnin geri kalanından ayırmanın en hızlı yolu renktir.
color özelliği ile harfi metinden tamamen farklı, canlı bir renge boyayabilirsiniz.
Daha da ileri giderek, harfin arkasına bir zemin rengi ( background ) atayabilir, hatta bu zemine bir görsel giydirebilirsiniz.
Bu teknik, harfi sadece bir yazı karakteri olmaktan çıkarıp, metnin içine gömülmüş bir "ikon" veya "grafik öğe" gibi gösterir.
Nefes Payı ve Çerçeveleme (Kutu Modeli)Büyüttüğünüz harfin diğer harflerin üzerine binmemesi veya onları çok sıkıştırmaması gerekir.
İşte burada Kutu Modeli devreye girer.
margin kullanarak harfin etrafındaki diğer kelimeleri itebilir ve ona özel bir alan açabilirsiniz.
padding ve border kullanarak harfi bir kutu içine alabilir, etrafına zarif bir çerçeve çizebilirsiniz.
Bu, dergi tasarımlarındaki o "kutulu başlangıç harfi" etkisini yaratır.
Derinlik ve Doku (Metin Efektleri) Harfin kağıttan yukarı doğru yükseldiği hissini vermek için text-shadow kullanabilirsiniz.
Doğru bir gölge kullanımı, düz bir tasarımı anında üç boyutlu hale getirir.
Ancak dikkat edilmelidir ki, bu özellikler sadece harfin kendisini etkiler; paragrafın geri kalan satır yapısını bozmaz.
<!DOCTYPE html>
<html lang="tr">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Modern Drop Cap - ::first-letter</title>
<link rel="stylesheet" href="style.css?v=1.0.150">
</head>
<body>
<div class="article">
<h2 class="title">Editorial Drop Cap</h2>
<p class="text">
Modern web tasarımında tipografi sadece okunabilirlik değil, aynı zamanda bir deneyimdir.
İlk harfin güçlü bir şekilde vurgulanması, okuyucunun dikkatini çeker ve içeriğe profesyonel
bir giriş hissi kazandırır. Bu teknik, dijital dünyada klasik dergi estetiğini yeniden
canlandırır.
</p>
</div>
</body>
</html>
*,
*::before,
*::after {
box-sizing: border-box;
}
body {
margin: 0;
padding: 40px;
font-family: 'Inter', 'Segoe UI', sans-serif;
background: radial-gradient(circle at top, #0f172a, #020617);
color: #e2e8f0;
display: flex;
justify-content: center;
}
/* container */
.article {
max-width: 700px;
}
/* başlık */
.title {
font-size: 28px;
margin-bottom: 20px;
color: #cbd5f5;
}
/* paragraf */
.text {
font-size: 17px;
line-height: 1.8;
color: #cbd5f5;
}
/* 🔥 MAGIC: ::first-letter */
.text::first-letter {
float: left;
font-size: 70px;
line-height: 1;
font-weight: 700;
margin-right: 14px;
margin-top: 6px;
padding: 10px 16px;
border-radius: 12px;
background: linear-gradient(135deg, #6366f1, #22d3ee);
color: white;
box-shadow:
0 10px 25px rgba(99, 102, 241, 0.4),
inset 0 0 10px rgba(255, 255, 255, 0.2);
backdrop-filter: blur(6px);
}
İlk Satırın Gücü / Lead Line ::first-line
Bu sözde öğe, bir blok elementin sadece ilk satırını hedefler.
Ancak buradaki "ilk satır" kavramı sabit değil, dinamiktir.
Ekran boyutu değiştikçe, pencere daraldıkça veya font boyutu arttıkça, o ilk satıra sığan kelime sayısı değişir.
::first-line buna anlık olarak adapte olur; hangi kelimeler yukarıdaysa sadece onları boyar.
Okuma Deneyimi: Genellikle makale girişlerinde ilk cümleyi veya satırı font-weight: bold veya text-transform: uppercase yapmak, okuyucunun içeriği taramasını kolaylaştırır.
Kullanıcıya "Burada önemli bir şey başlıyor, odaklan" mesajı verir.
Kullanılabilen ÖzelliklerTıpkı ::first-letter gibi, bu öğe de kısıtlı bir stil kümesini destekler.
Genellikle font ayarları, renkler ve arka planlar değiştirilebilir; ancak marjin veya padding gibi kutu modeli özellikleri her tarayıcıda tutarlı çalışmayabilir.
Teknik Kısıt: "Blok" Zorunluluğu ::first-line seçicisi sadece "blok seviyesindeki" kaplayıcılarda (p, div, article) çalışır.
Eğer bir span etiketi gibi satır içi bir elemente bu stili uygularsanız, tarayıcı bunu görmezden gelir.
Çünkü inline elementlerin teknik olarak "satırları" yoktur, onlar satırın kendisidir.
Hiyerarşi ve Katmanlaşma Eğer aynı paragraf için hem ::first-letter hem de ::first-line tanımlanırsa ne olur?
İlk harf, teknik olarak ilk satırın içindedir. Ancak CSS hiyerarşisinde ::first-letter daha spesifiktir ve önceliğe sahiptir.
Yani ilk satırı mavi, ilk harfi kırmızı yaparsanız; ilk harf kırmızı kalır, geri kalan satır mavi olur. İlk harf, ilk satırın stilini miras almaz, onu ezer.
<!DOCTYPE html>
<html lang="tr">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Lead Line - ::first-line</title>
<link rel="stylesheet" href="style.css?v=1.0.150">
</head>
<body>
<div class="article">
<h2 class="title">Lead Line Highlight</h2>
<p class="text">
Modern içerik tasarımında ilk satır, okuyucunun dikkatini yakalayan en kritik alandır.
Bu alan doğru vurgulandığında, kullanıcı içeriğe daha hızlı adapte olur ve okuma
deneyimi daha akıcı hale gelir. Bu teknik, özellikle blog ve editorial tasarımlarda
sıkça kullanılır.
</p>
</div>
</body>
</html>
*,
*::before,
*::after {
box-sizing: border-box;
}
body {
margin: 0;
padding: 40px;
font-family: 'Inter', 'Segoe UI', sans-serif;
background: radial-gradient(circle at top, #0f172a, #020617);
color: #e2e8f0;
display: flex;
justify-content: center;
}
/* container */
.article {
max-width: 720px;
}
/* başlık */
.title {
font-size: 28px;
margin-bottom: 20px;
color: #cbd5f5;
}
/* paragraf */
.text {
font-size: 17px;
line-height: 1.8;
color: #cbd5f5;
}
/* 🔥 MAGIC: ::first-line */
.text::first-line {
font-weight: 600;
letter-spacing: 0.4px;
background: linear-gradient(90deg, rgba(99,102,241,0.25), rgba(34,211,238,0.15));
color: #e0e7ff;
/* subtle glow */
text-shadow: 0 0 8px rgba(99,102,241,0.3);
}
Kullanıcı Seçimi ve Markalama ::selection
::selection sözde elementi, bir web sayfasında kullanıcının fare imleciyle tarayarak veya mobilde parmağıyla basılı tutarak "işaretlediği" metin parçasını hedefler.
Bu, kullanıcının içerikle en yoğun etkileşime girdiği andır; çünkü bir metni seçmek, genellikle onu kopyalamak, araştırmak veya daha dikkatli okumak niyetini taşır.
Normal şartlarda metin seçimi rengi ( genellikle o klasik mavi ), tarayıcı veya işletim sistemi tarafından belirlenir.
::selection seçicisi, bu sistem seviyesindeki kontrolü elinize almanızı ve tarayıcıya "Hayır, benim sitemde seçim rengi işletim sisteminin mavisi değil, benim markamın rengi olacak" demenizi sağlar.
Standarttan Kaçış Varsayılan olarak tüm tarayıcılar, seçilen metni "mavi arka plan üzerine beyaz yazı" olarak gösterir.
Bu standart, güvenli ama sıkıcıdır.
Marka Kimliği: ::selection kullanarak bu rengi markanızın kurumsal rengine (örneğin sarı arka plan üzerine siyah yazı) dönüştürebilirsiniz.
Detaylardaki Şıklık: Kullanıcı sitenizden bir metni kopyalamak istediğinde markanızın renkleriyle karşılaşması, sitenin ne kadar özenle tasarlandığına dair bilinçaltına güçlü bir mesaj gönderir.
Bu, "tasarımın bittiği yerde bile deneyimin devam ettiğini" gösterir.
Erişilebilirlik Uyarısı Burada seçilen renklerin kontrast oranının yüksek olması, metnin okunabilirliği açısından hayati önem taşır.
Sadece color, background-color ve text-shadow özellikleri değiştirilebilir.
Profesyonel İpucu: Gölge TemizliğiEğer normal metninizde görsel efekt olarak text-shadow varsa, seçim anında bu gölge genellikle okunabilirliği bozar ve "kirli" bir görüntü oluşturur.
En iyi pratik, seçim durumunda gölgeyi sıfırlamaktır: ::selection { text-shadow: none; }. Bu, seçilen metnin jilet gibi keskin ve net görünmesini sağlar.
Bölgesel (Scoped) ÖzelleştirmeSeçim rengi tüm sitede aynı olmak zorunda değildir.
Sitenizin siyah arka planlı bir "Dark Mode" bölümü varsa, orada sarı seçim rengi kullanırken; beyaz arka planlı bölümde mor seçim rengi kullanabilirsiniz.
Örneğin: p.dark-theme::selection { ... } diyerek, özelleştirmeyi sadece o paragrafa veya bölüme özel hale getirebilirsiniz.
<!DOCTYPE html>
<html lang="tr">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Branded Selection - ::selection</title>
<link rel="stylesheet" href="style.css?v=1.0.150">
</head>
<body>
<div class="article">
<h2 class="title">Custom Selection Experience</h2>
<p class="text">
Bu metni seçmeyi deneyin. Modern web tasarımında kullanıcı etkileşiminin her anı önemlidir.
Metin seçimi bile marka kimliğinin bir parçası olabilir. Doğru renkler ve kontrast ile,
kullanıcıya daha temiz ve profesyonel bir deneyim sunabilirsiniz.
</p>
<p class="text highlight">
Bu alan ise farklı bir selection stiline sahiptir. Scoped selection kullanımı sayesinde
sayfanın farklı bölümlerinde farklı kullanıcı deneyimleri oluşturabilirsiniz.
</p>
</div>
</body>
</html>
*,
*::before,
*::after {
box-sizing: border-box;
}
body {
margin: 0;
padding: 40px;
font-family: 'Inter', 'Segoe UI', sans-serif;
background: radial-gradient(circle at top, #0f172a, #020617);
color: #e2e8f0;
display: flex;
justify-content: center;
}
/* container */
.article {
max-width: 720px;
}
/* başlık */
.title {
font-size: 28px;
margin-bottom: 20px;
color: #cbd5f5;
}
/* metin */
.text {
font-size: 17px;
line-height: 1.8;
margin-bottom: 20px;
color: #cbd5f5;
text-shadow: 0 2px 8px rgba(0, 0, 0, 0.4);
}
/* 🔥 GLOBAL SELECTION */
::selection {
background: linear-gradient(135deg, #6366f1, #22d3ee);
color: #020617;
/* kritik: temiz görüntü */
text-shadow: none;
}
/* 🔥 SCOPED SELECTION */
.highlight::selection {
background: #facc15;
color: #020617;
}
Kullanıcı Arayüzü İpuçları ve Yer Tutucular ::placeholder
Form giriş alanlarının (input, textarea) içinde, kullanıcı henüz bir değer girmemişken görünen geçici ve silik metne stil uygular.
Bu metin, teknik bir veri değil, kullanıcıya kutunun amacını anlatan bir rehberdir.
Tarayıcıların varsayılan yer tutucu stilleri genellikle çok açık gri ve standarttır.
Bu, markanızın renk paletiyle uyumsuz olabilir veya bazı ekranlarda okunmayacak kadar silik kalabilir.
::placeholder kullanarak bu metnin rengini değiştirebilir, font boyutunu küçültebilir veya onu italik yaparak gerçek metinden ayırt edilmesini kolaylaştırabilirsiniz.
Kullanıcı Deneyimi (UX) İyileştirmesi: Yer tutucu metnin, kullanıcı asıl metni yazdıktan sonraki renkten çok farklı olmaması, tasarımda tutarsızlık yaratabilir; ancak birebir aynı olması da kullanıcının kutuyu "zaten dolu" sanmasına neden olabilir.
Bu nedenle tasarımcılar genellikle yer tutucular için opacity değerini düşürür veya daha yumuşak bir renk tonu tercih ederler.
Teknik Sınırlamalar: Bu sözde öğe, yalnızca color, font-style, font-weight gibi metin özelliklerini etkileyebilir.
Kutu modeli ( width, , height , margin ) gibi düzen özellikleri, yer tutucunun kendisine değil, onu kapsayan input elementine ait olduğu için burada çalışmaz.
Profesyonel İpucu: Firefox ve Opacity Tuzağı Geliştiricilerin en sık düştüğü tuzak şudur: Placeholder rengini kırmızı yaparsınız, Chrome'da kırmızı görünür ama Firefox'ta soluk bir kırmızı çıkar.
Bunun nedeni, Firefox'un varsayılan olarak yer tutuculara opacity: 0.5 gibi bir değer atamasıdır.
Renklerin tüm tarayıcılarda canlı ve aynı görünmesi için mutlaka ::placeholder { opacity: 1; } tanımını eklemelisiniz.
Kritik Uyarı: Yer Tutucu "Etiket" DeğildirModern tasarımlarda bazen yer kazanmak için <label> kaldırılıp, sadece placeholder kullanılır.
Bu ciddi bir Erişilebilirlik hatasıdır.
Kullanıcı yazı yazmaya başladığı anda yer tutucu kaybolur.
Eğer kullanıcı bir an dikkatini dağıtırsa, "Ben bu kutuya ne yazıyordum?" sorusuna cevap bulamaz ( Geçici Hafıza Sorunu ).
Animasyon ve Geçişler Yer tutucular da transition özelliğini destekler.
Örneğin: Input'a tıklandığında (:focus) yer tutucunun yavaşça sağa kaymasını veya silikleşmesini sağlayarak
( input:focus::placeholder { ... } ) hoş bir mikro-etkileşim yaratabilirsiniz.
<!DOCTYPE html>
<html lang="tr">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Modern Placeholder UX</title>
<link rel="stylesheet" href="style.css?v=1.0.150">
</head>
<body>
<div class="form-container">
<h2 class="title">Login Form</h2>
<input type="text" placeholder="Kullanıcı adınızı girin">
<input type="email" placeholder="E-posta adresiniz">
</div>
</body>
</html>
*,
*::before,
*::after {
box-sizing: border-box;
}
body {
margin: 0;
height: 100vh;
display: flex;
justify-content: center;
align-items: center;
font-family: 'Inter', 'Segoe UI', sans-serif;
background: radial-gradient(circle at top, #0f172a, #020617);
}
/* container */
.form-container {
width: 320px;
display: flex;
flex-direction: column;
gap: 16px;
}
/* başlık */
.title {
color: #cbd5f5;
margin-bottom: 10px;
}
/* input */
input {
padding: 14px 16px;
border-radius: 12px;
border: 1px solid rgba(148, 163, 184, 0.2);
background: rgba(15, 23, 42, 0.6);
color: #e2e8f0;
backdrop-filter: blur(10px);
outline: none;
transition: all 0.3s ease;
}
/* hover/focus */
input:focus {
border-color: #6366f1;
box-shadow: 0 0 0 2px rgba(99, 102, 241, 0.3);
}
/* 🔥 placeholder base */
input::placeholder {
color: #94a3b8;
opacity: 1;
transition: all 0.3s ease;
}
/* 🔥 focus animasyonu */
input:focus::placeholder {
transform: translateX(6px);
opacity: 0.4;
}
/* 🔥 subtle hover */
input:hover::placeholder {
opacity: 0.8;
}
Liste İşaretçisi ve Numaralandırma ::marker
Bu sözde öğe, Düzenlenmiş (ol) ve Düzensiz ( ul ) listelerin başında yer alan otomatik işaretçiyi veya summary etiketinin ok işaretini doğrudan hedefler.
CSS'in modern dönemine kadar, bu küçük noktaları veya sayıları ana metinden bağımsız olarak stilize etmek imkansıza yakındı.
Eskiden bir listenin maddesini siyah, başındaki noktayı kırmızı yapmak için geliştiriciler listenin varsayılan stilini kapatır
(list-style: none), ardından ::before kullanarak sahte bir nokta yaratırdı.
::marker bu karmaşayı ortadan kaldırır.
değiştirebilirsiniz. Artık doğrudan işaretçiyi seçip rengini veya fontunu değiştirebilirsiniz.
Estetik Özgürlük ve İçerik Yönetimi Bu seçici sadece renk değiştirmekle kalmaz, content özelliği sayesinde sıkıcı noktaları emojilerle veya özel karakterlerle değiştirmenize olanak tanır.
Örneğin: li::marker { content: "✅ "; } yazarak, standart bir listeyi anında bir "Yapılacaklar Listesi"ne dönüştürebilirsiniz.
Teknik Kısıtlamalar (Kutu Modeli) ::marker her CSS özelliğini desteklemez.
Tarayıcılar bu öğe üzerinde sadece metin odaklı özelliklere izin verir, color, font-size, font-family ve content güvenle kullanılabilir.
Ancak margin, padding, background veya width gibi yerleşim özellikleri burada çalışmaz.
İşaretçinin konumunu değiştirmek için hala ana li etiketinin padding değerleriyle oynamanız gerekir.
Dinamik Sayaçlar ve Otomasyon Sadece statik ikonlar değil, CSS counter() fonksiyonu ile birleştiğinde ::marker çok daha güçlü hale gelir.
Örneğin: Standart "1, 2, 3" sıralamasını "Bölüm 1:", "Bölüm 2:" şeklinde değiştirmek için
content: "Bölüm " counter(list-item) ": "; kodu kullanılır.
Bu sayede HTML yapısını bozmadan otomatik artan özel başlıklar yaratabilirsiniz.
Erişilebilirlik ve Tarayıcı DesteğiGörsel özelleştirmeler yaparken ekran okuyucuları unutmamak gerekir.
::marker ile eklediğiniz içerik, çoğu yardımcı teknoloji tarafından seslendirilir.
Eğer sadece dekoratif bir amaçla content: "★"; kullanıyorsanız, görme engelli bir kullanıcı her madde başında "Yıldız" kelimesini duyabilir.
Bu yüzden sembol seçiminde anlam bütünlüğüne dikkat edilmelidir.
Safari ve Firefox bu özelliği tam desteklerken, çok eski tarayıcılarda varsayılan stil devreye girer.
<!DOCTYPE html>
<html lang="tr">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Feature List</title>
<link rel="stylesheet" href="style.css?v=1.0.150">
</head>
<body>
<section class="features">
<h2>Platform Özellikleri</h2>
<ul class="feature-list">
<li>Hızlı ve optimize edilmiş performans</li>
<li>Kullanıcı dostu modern arayüz</li>
<li>Güvenli veri yönetimi</li>
<li>Kolay entegrasyon altyapısı</li>
</ul>
</section>
</body>
</html>
*,
*::before,
*::after {
box-sizing: border-box;
}
body {
margin: 0;
padding: 60px 20px;
font-family: 'Inter', sans-serif;
background: #f8fafc;
color: #1e293b;
display: flex;
justify-content: center;
}
/* container */
.features {
max-width: 700px;
}
/* başlık */
.features h2 {
font-size: 28px;
margin-bottom: 25px;
color: #0f172a;
}
/* liste */
.feature-list {
padding-left: 24px;
}
/* item */
.feature-list li {
font-size: 17px;
line-height: 1.8;
margin-bottom: 14px;
color: #334155;
}
/* 🔥 MODERN MARKER */
.feature-list li::marker {
content: "✦ ";
color: #6366f1;
font-size: 18px;
font-weight: bold;
}
Gelişmiş Pseudo-Elementler Sözde Öğeler (Pseudo-Elements)
Buraya kadar metinlerin "ilk satırı" veya "işaretçisi" gibi basit parçaları stilize ettik, ancak modern CSS, bundan çok daha derinlere inebilir.
Sırada inceleyeceğimiz seçiciler, HTML sayfanızın yüzeysel katmanından çıkıp, tarayıcının kendi oluşturduğu arayüzlere ve modern bileşen mimarisine ( Shadow DOM ) erişmemizi sağlar.
Bazı HTML elementleri, sadece basit bir etiket değildir; içlerinde tarayıcı tarafından üretilen gizli bir mekanizma barındırırlar.
Dahili UI KontrolleriBir dosya yükleme butonu (input type="file"), aslında yanında bir buton ve dosya ismi alanı olan karmaşık bir yapıdır.
Eskiden bunlara müdahale edemezdik, ancak yeni nesil sözde öğelerle artık bu "yerli" butonları stilize edebiliyoruz.
Top Layer (En Üst Katman) Modern web'de Dialog pencereleri veya Tam Ekran modları, sayfanın z-index savaşlarından bağımsız, en üstte bir katmanda yaşar. Bu katmanın arka planını ve davranışını yönetmek için özel seçicilere ihtiyacımız vardır.
Medya ve Geri Bildirim KatmanıWeb sadece statik metin değildir; videolar, ses dosyaları ve kullanıcı etkileşimleri barındırır.
Bir videonun içindeki altyazıların fontunu değiştirmek veya kullanıcının yanlış yazdığı bir kelimenin altını çizen o kırmızı dalgalı çizgiyi özelleştirmek, standart CSS seçicileriyle mümkün değildir.
Bu gruptaki sözde öğeler, medya oynatıcıların ve tarayıcı imla denetiminin iç yapısına kanca atmanızı sağlar.
Modern Mimari: Shadow DOM ve Kapsülleme Modern web geliştirme, Web Bileşenleri üzerine kuruludur.
Bu bileşenler, dış dünyadan etkilenmemek için kendilerini Shadow DOM adı verilen bir fanus içine alırlar.
Sınırları Kontrollü AşmakNormal CSS seçicileri Shadow DOM'un içine giremez.
Ancak bazen dışarıdan bir bileşenin belirli bir parçasını boyamanız gerekir.
İşte bu noktada, kapsülleme kurallarını ihlal etmeden, bileşenin izin verdiği noktalara erişmemizi sağlayan ::part() ve ::slotted() gibi fonksiyonel sözde öğeler devreye girer.
Dosya Yükleme Butonu ::file-selector-button
<input type="file"> etiketi, web tarihinin en eski, en işlevsel ama tasarım açısından en sorunlu bileşenlerinden biridir.
Bu element aslında tek parça değildir; tarayıcı onu arka planda ( Shadow DOM içinde ) iki parçaya böler: Bir buton ("Dosya Seç") ve seçilen dosyanın adını gösteren bir metin alanı.
::file-selector-button sözde öğesi, işte bu içyapıdaki buton parçasını cerrah titizliğiyle çekip almanızı ve stilize etmenizi sağlar.
Tarihsel Miras: "Çirkin Ördek Yavrusu" SendromuYakın geçmişe kadar tarayıcılar, bu butona dokunmamıza izin vermezdi.
Chrome'da gri ve kaba, Safari'de parlak ve yuvarlak, Windows'ta ise köşeli görünürdü.
Bu durum, özenle tasarlanmış modern bir web sitesinin ortasında, 90'lardan kalma bir işletim sistemi parçası unutulmuş gibi durmasına neden olurdu.
Eski "Hack" Yöntemi: Görünmez Input Geliştiriciler bu çirkinliği gizlemek için yıllarca "Label Hack" yöntemini kullandı: Gerçek input'u
opacity: 0 veya display: none ile gizle, önüne sahte bir label butonu koy ve tıklamayı ona yönlendir.
Bu yöntem çalışırdı ancak erişilebilirlik sorunlarına ve klavye navigasyonunda hatalara yol açardı.
Modern Çözüm ve Doğrudan ErişimArtık hile yapmaya gerek yok. Bu sözde öğe sayesinde, dosya yükleme butonuna standart bir button muamelesi yapabilirsiniz.
Standart Buton Özellikleri Arka plan rengini (background), kenar yuvarlaklığını (border-radius), iç boşlukları (padding) ve yazı tipini özgürce değiştirebilirsiniz.
Hatta margin-right vererek, buton ile yanındaki dosya ismi metni arasındaki mesafeyi açabilirsiniz.
Hover ve Active Durumları Bu sözde öğeyi, sözde sınıflarla birleştirebilirsiniz.
input::file-selector-button:hover diyerek, kullanıcı faresiyle butonun üzerine geldiğinde rengini değiştirebilirsiniz.
Eski İsimler Kısıtlamaları (Vendor Prefixes)Bu özellik standartlaşmadan önce tarayıcılar farklı isimler kullanıyordu.
Webkit tabanlı tarayıcılar ( Chrome, Safari) ::-webkit-file-upload-button kullanırken, eski Edge/IE ::-ms-browse kullanıyordu.
Modern kodlarda standart ismi kullanmak yeterlidir ancak eski sistemler için bu takma adları bilmekte fayda vardır.
Ulaşılamayan Metin: Dosya İsmiBurada önemli bir ayrım var: Biz sadece butonu stillendiriyoruz.
Butonun yanında çıkan "Dosya seçilmedi" veya "fotograf.jpg" yazısı, tarayıcının kontrolündedir ve doğrudan bir CSS seçicisiyle ( henüz ) hedeflenemez.
O metnin fontunu değiştirebilirsiniz ( input'un kendisine font vererek), ancak içeriğini veya tam konumunu değiştirmek hala zordur.
<!DOCTYPE html>
<html lang="tr">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Upload UI</title>
<link rel="stylesheet" href="style.css?v=1.0.150">
</head>
<body>
<div class="upload-card">
<h2>Dosya Yükle</h2>
<p>Dosyanızı seçin veya yüklemek için tıklayın</p>
<input type="file">
</div>
</body>
</html>
*,
*::before,
*::after {
box-sizing: border-box;
}
body {
margin: 0;
height: 100vh;
display: flex;
justify-content: center;
align-items: center;
font-family: 'Inter', sans-serif;
background: linear-gradient(135deg, #f1f5f9, #e2e8f0);
}
/* card */
.upload-card {
background: white;
padding: 30px;
border-radius: 16px;
width: 320px;
text-align: center;
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.08);
}
/* title */
.upload-card h2 {
margin-bottom: 10px;
color: #0f172a;
}
/* text */
.upload-card p {
font-size: 14px;
color: #64748b;
margin-bottom: 20px;
}
/* input container hissi */
input[type="file"] {
width: 100%;
padding: 20px;
border: 2px dashed #cbd5f5;
border-radius: 12px;
background: #f8fafc;
cursor: pointer;
transition: all 0.3s ease;
}
/* hover alan efekti */
input[type="file"]:hover {
border-color: #6366f1;
background: #eef2ff;
}
/* 🔥 BUTTON STYLING */
input[type="file"]::file-selector-button {
border: none;
padding: 10px 18px;
margin-right: 12px;
border-radius: 8px;
background: #6366f1;
color: white;
font-size: 14px;
cursor: pointer;
transition: all 0.25s ease;
}
/* hover */
input[type="file"]::file-selector-button:hover {
background: #4f46e5;
}
/* active */
input[type="file"]::file-selector-button:active {
transform: scale(0.96);
}
Arka Plan Perdesi ::backdrop
::backdrop, modern webin yerleşik "Sinema Modu" gibidir.
Bir öğe sahneye çıktığında, arkada kalan tüm dünyayı örten o sihirli katmandır.
Bu sözde öğe, herhangi bir HTML elemanının içinde değil, tarayıcının Top Layer dediğimiz özel yığıt bağlamında, viewport'un hemen önünde oluşturulur.
Kullanıcının odağını öne çıkan içeriğe sabitlemek ve arkadaki içeriği görsel olarak pasifize etmek temel açatır.
Tetikleyiciler: Ne Zaman Görünür?::backdrop'ı sıradan bir div'e ekleyemezsiniz, yalnızca belirli API'ler bu katmanı oluşturur:
- <dialog> elementi, .showModal() metodu ile açıldığında.
- Herhangi bir element Fullscreen API ile tam ekran yapıldığında.
- Yeni nesil Popover API kullanıldığında.
Görsel Tasarım: Buzlu Cam Efekti Varsayılan olarak tarayıcılar ( User Agent Stylesheet ), bu katmana yarı saydam siyah bir renk atar , ancak kontrol tamamen sizdedir.
Özellikle backdrop-filter özelliği ile birlikte kullanıldığında modern arayüzlerin vazgeçilmezi olur.
Arkadaki içeriği blur(10px) ile bulanıklaştırarak, tıpkı iOS veya Windows Aero arayüzlerindeki gibi bir derinlik algısı yaratabilirsiniz.
Miras Almaz (No Inheritance)En sık yapılan hata, backdrop'ın ana elementten stil miras alacağını sanmaktır.
::backdrop teknik olarak elementin bir çocuğu değil, kardeşi ( hatta ağacın en tepesindeki uzak kuzeni ) gibi davranır.
Bu yüzden font veya değişkenleri bazen yeniden tanımlamanız gerekebilir.
Z-Index Savaşlarına SonGeçmişte modal arkasına perde koymak için z-index: 9999 gibi çılgın değerler verirdik.
::backdrop, Top Layer mekanizması sayesinde sayfanın z-index bağlamından tamamen bağımsızdır.
Her zaman en üsttedir, çakışma yaratmaz.
Top Layer ve z-index yığını ::backdrop nerede durur; normal yığıttan neden ayrıdır?
::backdrop rastgele bir
elemana yazılamaz; dialog.showModal(), tam ekran API veya
popover gibi bir Top Layer tetikleyicisi olmadan
oluşmaz.
::backdrop
Sayfanın geri kalanını karartan katman; modalın
altında, yine de tüm sayfa yığıtının üstünde
Top Layer kutusunun içinde sıra: önce perde (::backdrop), üzerinde asıl diyalog. Bu ikili birlikte, alttaki
normal z-index dünyasının tamamının üzerine çıkar.
::backdrop ile diyalog, normal
z-index yarışına girmez; Top Layer’da perde altta, içerik üstte sıralanır — ikisi
de sayfa yığıtının üzerindedir.
<!DOCTYPE html>
<html lang="tr">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Glass Modal</title>
<link rel="stylesheet" href="style.css?v=1.0.150">
</head>
<body>
<button class="open-btn">Modal Aç</button>
<dialog id="modal">
<h2>Bildirim</h2>
<p>Bu modern bir modal örneğidir. Arka plan blur efekti ile pasif hale getirilmiştir.</p>
<button class="close-btn">Kapat</button>
</dialog>
<script src="script.js?v=1.0.150"></script>
</body>
</html>
*,
*::before,
*::after {
box-sizing: border-box;
}
body {
margin: 0;
height: 100vh;
display: flex;
justify-content: center;
align-items: center;
font-family: 'Inter', sans-serif;
background: linear-gradient(135deg, #6366f1, #22d3ee);
}
/* aç butonu */
.open-btn {
padding: 14px 28px;
border: none;
border-radius: 10px;
background: #0f172a;
color: white;
cursor: pointer;
}
/* modal */
dialog {
border: none;
border-radius: 16px;
padding: 25px;
max-width: 320px;
background: rgba(255, 255, 255, 0.9);
backdrop-filter: blur(10px);
box-shadow: 0 20px 50px rgba(0, 0, 0, 0.3);
}
/* 🔥 BACKDROP */
dialog::backdrop {
background: rgba(15, 23, 42, 0.6);
backdrop-filter: blur(6px);
}
/* kapat */
.close-btn {
margin-top: 15px;
padding: 10px 20px;
border: none;
border-radius: 8px;
background: #6366f1;
color: white;
cursor: pointer;
}
const modal = document.getElementById('modal');
document.querySelector('.open-btn').onclick = () => modal.showModal();
document.querySelector('.close-btn').onclick = () => modal.close();
Not
WebVTT ayrıca ::cue-region pseudo-element'ini
tanımlamıştır, ancak bu özellik
hiçbir tarayıcıda desteklenmediği için pratik kullanımı mümkün değildir.
Bu
nedenle burada sadece
::cue örneği gösterilmiştir.
Video Alt Yazılarını Yönetmek ::cue
Web dünyasında video ve ses tüketimi arttıkça, bu içeriklerin herkes tarafından anlaşılabilir olması bir zorunluluk haline gelmiştir.
<video> ve <audio> etiketleri, <track> etiketi aracılığıyla harici metin dosyalarını ( WebVTT formatı ) okuyarak ekrana alt yazı basabilirler.
Ancak tarayıcıların varsayılan alt yazı stilleri genellikle basit, bazen okunması zor ve sitenizin tasarımından kopuktur.
İşte ::cue sözde elementi, bu standart görünüme müdahale etmenizi ve alt yazıları markanızın bir parçası haline getirmenizi sağlar.
Teknik Bağlam: Shadow DOM İçine SızmakBir video oynatıcısında alt yazı açıldığında, o metinler HTML sayfanızın normal akışında ( Light DOM ) bulunmaz.
Tarayıcı, video oynatıcısının kendi iç dünyasında ( User Agent Shadow DOM ) bu metinleri oluşturur.
::cue, CSS'in bu kapalı kutuya girmesine izin veren özel bir anahtardır. Video oynarken beliren o anlık metin satırlarını hedeflemenize olanak tanır.
Stil Yetenekleri ve Sınırlamalar: Neleri Değiştirebiliriz?::cue, diğer HTML elementleri kadar özgür değildir. Video akışını bozmamak ve performansı korumak için tarayıcılar burada sadece belirli özelliklere izin verir.
Bir alt yazıyı flexbox ile düzenleyemezsiniz veya ona karmaşık animasyonlar veremezsiniz. İzin verilen özellikler şunlarla sınırlıdır:
Farklı Senaryoları Hedeflemek- ::cue - Tüm alt yazılar için genel stil
- video::cue - Sadece videolar için
- ::cue(b) - WebVTT'deki kalın metinler
- ::cue(.sınıfAdı) - Özel sınıflı metinler
Okunabilirlik ve UX: Video Arka Planı Sorunu Video içeriği dinamiktir; arka plan sürekli değişir (siyah olur, beyaz olur, karmaşık desenler içerir).
Eğer sadece color: white; verirseniz, video sahnesi beyaza döndüğünde alt yazı kaybolur.
Altın Kural: Kontrastı KoruProfesyonel yayıncılar (Netflix, YouTube vb.) genellikle metnin arkasına yarı saydam siyah bir arka plan ekler.
Bunu sağlamak için: ::cue { background-color: rgba(0, 0, 0, 0.6); color: white; } kullanımı en güvenli yoldur.
Alternatif olarak, arka plan kutusu istemiyorsanız güçlü bir text-shadow kullanarak harflerin etrafına siyah bir kontür etkisi verebilirsiniz. Bu, metnin videodan "ayrılmasını" sağlar.
İçsel WebVTT Etiketleri WebVTT formatı sadece düz metin değildir. İçinde seslendiren kişiyi belirtmek ( Voice Span ) veya vurgu yapmak için etiketler kullanılabilir.
::cue(v[voice="Narrator"]) gibi gelişmiş seçicilerle, sadece "Anlatıcı"nın konuştuğu satırları örneğin italik ve sarı yapabilirsiniz. Bu, izleyiciye kimin konuştuğunu görsel olarak kodlamanın harika bir yoludur.
<!DOCTYPE html>
<html lang="tr">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Subtitle Card</title>
<link rel="stylesheet" href="style.css?v=1.0.150">
</head>
<body>
<div class="video-card">
<div class="video-box">
<video controls>
<source src="info.mp4" type="video/mp4">
<track src="subtitles.vtt" kind="subtitles" srclang="tr" default>
</video>
</div>
<div class="video-info">
<h3>Streaming Subtitle Demo</h3>
<p>
Bu örnek, <strong>::cue</strong> ile altyazıların nasıl modern bir UI parçasına
dönüştürülebileceğini gösterir.
</p>
</div>
</div>
</body>
</html>
*,*,
*::before,
*::after {
box-sizing: border-box;
}
body {
margin: 0;
height: 100vh;
display: flex;
justify-content: center;
align-items: center;
font-family: 'Inter', sans-serif;
background: radial-gradient(circle at top, #020617, #020617);
}
/* 🔥 CARD */
.video-card {
width: 520px;
border-radius: 16px;
background: rgba(15, 23, 42, 0.9);
box-shadow: 0 20px 60px rgba(0, 0, 0, 0.6);
overflow: hidden;
}
/* 🎬 video alanı */
.video-box {
width: 100%;
background: black;
}
.video-box video {
width: 100%;
display: block;
}
/* 📝 alt panel */
.video-info {
padding: 16px 18px;
}
.video-info h3 {
margin: 0 0 8px;
font-size: 16px;
color: #e2e8f0;
}
.video-info p {
margin: 0;
font-size: 14px;
color: #94a3b8;
line-height: 1.5;
}
/* 🔥 SUBTITLE */
video::cue {
color: white;
background: rgba(0, 0, 0, 0.65);
padding: 4px 10px;
border-radius: 6px;
text-shadow: 0 2px 6px rgba(0, 0, 0, 0.8);
}
WEBVTT
NOTE Demo subtitle file for ::cue styling
00:00:01.000 --> 00:00:04.000
<v Narrator>Bu bir anlatıcı konuşmasıdır.</v>
00:00:05.000 --> 00:00:08.000
<v Speaker>Bu farklı bir konuşmacıdır.</v>
00:00:09.000 --> 00:00:12.000
Bu <c.highlight>çok önemli</c> bir bilgidir.
00:00:13.000 --> 00:00:16.000
Alt yazılar <b>markalanabilir</b> ve özelleştirilebilir.
CSS ::grammar-error Yeşil Dalgalı Çizgiyi Yönetmek
Modern tarayıcılar artık sadece birer görüntüleyici değil, aynı zamanda gelişmiş birer metin editörüdür.
Bu editör yetenekleri sayesinde kullanıcıdan gelen içerik yalnızca ekrana basılmaz, aynı zamanda anlam, yapı ve dil kuralları açısından da analiz edilir.
Kullanıcı bir form doldururken veya bir metin kutusuna ( textarea, contenteditable ) yazı yazarken, tarayıcı arka planda çalışan yapay zeka destekli algoritmalarla metni analiz eder.
Bu analiz süreci yalnızca kelime kontrolü ile sınırlı değildir; aynı zamanda cümle akışı, zaman uyumu ve dilbilgisel bağlam da değerlendirilir.
Eğer kelimeler doğru yazılmışsa ama cümle yapısında, özne-yüklem uyumunda veya zaman eklerinde bir mantık hatası varsa; tarayıcı bunu
::grammar-error sözde elementi ile işaretler.
Bu işaretleme genellikle kullanıcıya görsel bir geri bildirim olarak sunulur ve çoğu zaman dalgalı alt çizgi şeklinde görünür.
Geliştiriciler ise bu davranışı tamamen kontrol edemez ancak ::grammar-error üzerinden bu görsel işaretin renk, stil veya
vurgu şeklini özelleştirebilir.
Yazım Hatası vs Dilbilgisi HatasıWeb geliştirmede bu iki kavram sıkça karıştırılır ancak teknik olarak tamamen ayrı mekanizmalardır:
Bu farkı anlamak, doğru kullanıcı geri bildirimi tasarlamak açısından kritik öneme sahiptir.
::spelling-error (Yazım Hatası): Kelimenin sözlükte bulunamamasıdır.
Genellikle kırmızı dalgalı çizgi ile gösterilir. ( "Geliyo" yerine "Geliyor")
Bu tür hatalar daha çok harf eksikliği, fazlalığı veya yanlış karakter kullanımı ile ilgilidir ve doğrudan kelime seviyesinde değerlendirilir.
::grammar-error (Dilbilgisi Hatası): Kelimeler doğrudur ancak yan yana gelişleri yanlıştır.
Genellikle yeşil veya mavi dalgalı çizgi ile gösterilir. ( "Ben eve gidiyoruz.")
Bu hatalar daha üst seviyede, yani cümle ve bağlam düzeyinde değerlendirilir ve genellikle daha karmaşık analizler gerektirir.
Bu yüzden ::grammar-error, kullanıcı deneyimi açısından daha akıllı ve bağlamsal bir geri bildirim mekanizması sunar.
Stil Manipülasyonu ve Sınırlar Cümle Yapısını Korumak
Dilbilgisi hataları, yazım hatalarından farklı olarak genellikle uzun cümle parçalarını kapsar.
Bu nedenle işaretlenen alan tek bir kelime değil, çoğu zaman birden fazla kelimenin oluşturduğu anlamsal bir bütün olabilir.
Eğer tarayıcılar burada font-size veya padding gibi yerleşim değiştiren özelliklere izin verseydi; kullanıcı yazı yazarken tüm paragraf sürekli titrer ve yer değiştirirdi.
Bu durum, özellikle canlı yazım sırasında okunabilirliği bozarve kullanıcı deneyimini ciddi şekilde olumsuz etkilerdi.
Bu yüzden tarayıcı motorları, ::grammar-error için yalnızca görsel vurgu sağlayan stillere izin verir.
Yani bu sözde element, belge akışını (document flow) değiştirmez; sadece mevcut metnin üzerine bindirilen bir işaretleme katmanı gibi davranır.
Bu yüzden, ::grammar-error sadece metnin üzerine uygulanan bir "makyaj" katmanıdır; metnin iskeletini değiştiren bir "estetik cerrahi" değildir.
Geliştirici açısından bakıldığında bu, stil verirken arka plan rengi, alt çizgi, outline veya text-decoration gibi güvenli özelliklerin tercih edilmesi gerektiği anlamına gelir.
Kısacası; amaç metni yeniden düzenlemek değil, kullanıcıya hatayı bozmadan ve dikkat dağıtmadan göstermektir.
|
Stil Türü
|
Açıklama ve Öneriler
|
|---|---|
|
Akıllı Alt Çizgiler
Text Decoration
|
Bu işin standardıdır.
|
|
Arka Plan Yönetimi
Background
|
Dilbilgisi hataları uzun
olabildiği için, arka plan rengi kullanırken
çok
dikkatli olunmalıdır.
|
|
Metin Rengi
Color
|
Metni tamamen silikleştirmek
veya hatayı vurgulamak
için
rengi
değiştirebilirsiniz.
|
|
Gölge ile Derinlik
Text Shadow
|
Metne hafif bir text-shadow ekleyerek, hatayı sayfadan hafifçe "yukarı" kaldırabilir veya bulanık bir gölge ile "odaklanılması gereken yer" hissi yaratabilirsiniz. |
|
Senaryo
|
Açıklama
|
|---|---|
|
Marka Uyumu (Branding)
|
Sitenizin teması yeşil
ağırlıklıysa, tarayıcının varsayılan yeşil
hata
çizgisi
görünmeyebilir.
|
|
Eğitim Uygulamaları
|
Bir dil öğrenme uygulaması yapıyorsanız, dilbilgisi hatalarını standart çizgiden daha kalın veya daha dikkat çekici bir arka planla vurgulamak isteyebilirsiniz. |
|
Karanlık Mod (Dark Mode)
|
Koyu arka planlarda varsayılan
renkler bazen kontrast sorununa yol
açar.
|
Kritik Not: Tarayıcı ve Dil Desteği Herkes Göremeyebilir
Bu özellik, web geliştirme literatüründe Progressive Enhancement ( Kademeli İyileştirme ) prensibine mükemmel bir örnektir.
Bu prensibe göre, temel deneyim her kullanıcı için çalışır durumda kalırken, destekleyen tarayıcılarda ekstra görsel ve işlevsel iyileştirmeler devreye girer.
CSS dosyanıza bu kodu eklediğinizde, eski bir tarayıcı ( veya özelliği desteklemeyen bir sürüm gibi ) bu satırı okur,
"Ben bunu tanımıyorum" der ve hatasız bir şekilde o satırı atlar.
Bu davranış, CSS'in doğası gereği toleranslı ve kırılmaya dayanıklı bir dil olmasından kaynaklanır.
Yani siteniz çökmez, düzen bozulmaz; sadece o özel stil uygulanmamış olur, bu da geliştiriciye "korkmadan kullanma" özgürlüğü verir.
Bu nedenle ::grammar-error gibi deneysel veya sınırlı destekli özellikler, çekirdek işlevselliğe bağlı olmadan kullanılmalıdır.
Karar Mekanizması: Tarayıcı Kimin Sözünü Dinler?Kritik Nokta: Bir cümlenin dilbilgisi açısından hatalı olup olmadığına Chrome veya Firefox kendisi karar vermez.
Tarayıcılar, bu ağır işlem yükünü ( doğal dil işleme ) üstlenmek yerine, kullanıcının bilgisayarındaki İşletim Sistemine ( Windows, macOS, Android ) danışır.
Bu da aynı web sayfası, farklı cihazlarda farklı dilbilgisi sonuçları üretebilir anlamına gelir.
Örneğin: Bir kullanıcıda hata olarak işaretlenen bir cümle, başka bir kullanıcıda tamamen doğru kabul edilebilir.
Bu fark, sistem sözlükleri, dil paketleri ve kullanıcı ayarlarından kaynaklanır.
Ayrıca bazı sistemlerde dil denetimi tamamen kapalı olabilir, bu durumda ::grammar-error hiç tetiklenmez.
Bu yüzden geliştiriciler, bu özelliği bir garanti mekanizması olarak değil, yardımcı bir katman olarak değerlendirmelidir.
Kısacası; kontrol sizde değil, kullanıcı ortamındadır. Siz sadece bu sistemin ürettiği sonucu daha anlaşılır ve estetik hale getirirsiniz.
İşlem Akışı ::grammar-error Nasıl Tetiklenir?
Not: ::grammar-error geliştirici tarafından HTML'de oluşturulmaz; tarayıcı, dilbilgisi geri bildirimine göre bu sözde öğeyi otomatik ekler.
::grammar-error sözde öğesini dinamik olarak oluşturur. Bu öğe HTML kaynağında yoktur; geliştirici elle eklemez.
Not
Aşağıdaki canlı örnek, tamamen CSS’in yerleşik gücünü kullanmaktadır.
Ancak unutulmamalıdır ki; ::grammar-error seçicisinin çalışması, tarayıcınızın ve işletim sisteminizin o anki dil işleme yeteneğine bağlıdır.
Eğer daha tutarlı, tarayıcıdan bağımsız ve her kullanıcıda aynı kusursuz sonucu veren bir yapı kurmak isterseniz, JavaScript tabanlı harici dilbilgisi kütüphaneleri (LanguageTool vb.) kullanmak daha profesyonel bir çözüm olacaktır.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<link rel="stylesheet" href="style.css?v=1.0.150">
</head>
<body>
<section class="editor-container">
<h3>Modern Dilbilgisi Editörü</h3>
<p class="info-badge">Tarayıcınızın dil denetimi açıksa hataları görebilirsiniz.</p>
<div class="editor-area" contenteditable="true" spellcheck="true">
Ben dün akşam sinemaya gidiyoruz. (Dilbilgisi Hatası Örneği)
<br><br>
Yalnış yazılan kelimeler ise farklıdır. (Yazım Hatası Örneği)
</div>
<div class="legend">
<span class="item grammar">::grammar-error (Mor Vurgu)</span>
<span class="item spelling">::spelling-error (Turuncu Alt Çizgi)</span>
</div>
</section>
</body>
</html>
body {
background: #f8fafc;
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
font-family: system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;
margin: 20px;
}
.modern-card {
max-width: 850px;
width: 100%;
background: white;
border-radius: 28px;
box-shadow: 0 20px 35px -8px rgba(0, 0, 0, 0.1), 0 5px 10px -4px rgba(0, 0, 0, 0.05);
overflow: hidden;
border: 1px solid rgba(226, 232, 240, 0.6);
}
.card-header {
padding: 24px 28px 12px 28px;
border-bottom: 1px solid #eef2f6;
}
.card-header h3 {
display: flex;
align-items: center;
gap: 12px;
margin: 0 0 8px 0;
font-weight: 600;
color: #1e293b;
}
.card-header h3 i {
color: #10b981;
font-size: 1.6rem;
}
.title-badge {
background: #d1fae5;
color: #065f46;
font-size: 0.8rem;
font-weight: 600;
padding: 4px 10px;
border-radius: 40px;
letter-spacing: 0.3px;
margin-left: 10px;
}
.card-content {
padding: 20px 28px 28px 28px;
}
.demo-textarea::grammar-error {
/* Sıkıcı klasik yeşil çizgiyi, modern sarı-turuncu dalgalı çizgiye çeviriyoruz */
text-decoration: wavy underline #f59e0b;
text-decoration-thickness: 2.5px;
text-underline-offset: 5px;
background-color: rgba(245, 158, 11, 0.08);
border-radius: 4px;
}
.demo-textarea::spelling-error {
text-decoration: wavy underline #ef4444;
text-decoration-thickness: 2px;
background-color: rgba(239, 68, 68, 0.05);
}
.demo-textarea {
width: 100%;
padding: 20px;
font-size: 1.1rem;
line-height: 1.6;
border: 1.5px solid #e2e8f0;
border-radius: 20px;
background: #ffffff;
resize: vertical;
min-height: 180px;
box-sizing: border-box;
transition: border 0.2s ease, box-shadow 0.2s ease;
font-family: inherit;
color: #0f172a;
box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.02);
}
.demo-textarea:focus {
outline: none;
border-color: #10b981;
box-shadow: 0 0 0 4px rgba(16, 185, 129, 0.1), inset 0 2px 4px rgba(0, 0, 0, 0.02);
}
/* Güvenlik ve Açıklama Notları */
.info-grid {
display: flex;
flex-wrap: wrap;
gap: 16px;
margin-top: 24px;
}
.info-item {
flex: 1 1 200px;
background: #f1f5f9;
padding: 14px 18px;
border-radius: 18px;
border-left: 6px solid #10b981;
}
.info-item i {
color: #0d9488;
margin-right: 8px;
}
.info-item strong {
display: block;
margin-bottom: 6px;
color: #0f172a;
}
.info-item p {
margin: 4px 0;
font-size: 0.9rem;
color: #334155;
}
.security-badge {
display: inline-block;
background: #10b981;
color: white;
padding: 2px 10px;
border-radius: 30px;
font-size: 0.7rem;
font-weight: bold;
text-transform: uppercase;
letter-spacing: 0.5px;
margin-left: 6px;
}
.btn-group {
margin-top: 20px;
display: flex;
gap: 12px;
flex-wrap: wrap;
}
.btn {
background: white;
border: 1px solid #cbd5e1;
padding: 8px 16px;
border-radius: 40px;
font-size: 0.9rem;
font-weight: 500;
color: #334155;
cursor: pointer;
transition: all 0.15s;
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.03);
display: inline-flex;
align-items: center;
gap: 6px;
}
.btn:hover {
background: #f8fafc;
border-color: #94a3b8;
}
.btn i {
color: #64748b;
}
.hierarchy-badge-blue {
background: #dbeafe;
color: #1e40af;
padding: 4px 10px;
border-radius: 30px;
font-size: 0.8rem;
font-weight: 600;
}
/* Yazım hatası (Kırmızı) - Kalın ve kesik çizgi */
.demo-textarea::spelling-error {
text-decoration: wavy underline #ef4444;
text-decoration-thickness: 2.5px;
text-underline-offset: 4px;
background-color: rgba(239, 68, 68, 0.08);
border-radius: 3px;
}
.demo-textarea::grammar-error {
text-decoration: wavy underline #f59e0b;
text-decoration-thickness: 3px;
text-underline-offset: 5px;
background-color: rgba(245, 158, 11, 0.12);
border-radius: 4px;
}
CSS ::spelling-error Kırmızı Çizginin Ötesi
İnternet kullanıcılarının en aşina olduğu görsel geri bildirimlerden biri, yanlış yazılan bir kelimenin altındaki o parlak kırmızı çizgidir.
Bu görsel uyarı, kullanıcıya anında geri bildirim sağlayarak yazım hatalarını fark etmeyi kolaylaştırır ve özellikle form girişlerinde
hata oranını ciddi şekilde azaltır.
Bu, tarayıcının veya işletim sisteminin "Bu kelimeyi sözlükte bulamadım" deme şeklidir.
Bu kontrol mekanizması genellikle aktif dil sözlüğüne bağlıdır ve kullanıcının seçtiği dile göre farklı sonuçlar üretebilir.
Ancak varsayılan bu stil, her tasarım diline uygun olmayabilir.
Özellikle koyu temalı ( Dark Mode ) arayüzlerde veya pastel tonlu tasarımlarda, varsayılan kırmızı çok agresif ve okunaksız kalabilir.
Ayrıca marka kimliği güçlü projelerde, bu varsayılan stil tasarım bütünlüğünü bozabilir ve arayüzde yabancı bir öğe gibi görünebilir.
::spelling-error, bu standart uyarıyı sitenizin estetiğine uydurmanıza olanak tanır.
Bu sayede hem kullanıcıya hata bilgisini vermeye devam eder, hem de bu uyarıyı daha yumuşak, daha uyumlu ve daha kontrollü bir şekilde sunabilirsiniz.
Teknik Fark: Yazım vs. DilbilgisiBu iki kavramı birbirinden ayırmak, doğru seçiciyi kullanmak için kritiktir:
Çünkü biri kelime seviyesinde çalışırken, diğeri cümle seviyesinde analiz yapar ve bu fark doğrudan stil stratejinizi etkiler.
Bu ayrımı doğru anlamak, kullanıcıya verilen geri bildirimin hem doğru hem de anlamlı olmasını sağlar.
Kısacası; ::spelling-error hızlı ve doğrudan bir kontrol mekanizması sunarken, ::grammar-error daha derin ve bağlamsal bir analiz yapar.
Stil Özgürlüğü ve Sınırlar Neleri Boyayabiliriz?
Tarayıcıların ::spelling-error üzerinde neden bu kadar katı kuralları olduğunu anlamak için bir senaryo hayal edin:
Kullanıcı hızlıca yazı yazıyor ve bir harf hatası yapıyor.
Eğer siz CSS ile "Hatalı kelimenin font boyutunu büyüt (font-size: 20px)" veya "Kenarına boşluk ekle (margin: 5px)" demiş olsaydınız ne olurdu?
Hatalı kelime aniden şişer, satırdaki diğer kelimeleri iter ve tüm paragrafın düzeni ( Layout ) anlık olarak bozulurdu.
Bu sadece görsel bir problem değildir; aynı zamanda tarayıcının her değişiklikte tüm sayfayı yeniden hesaplamasına neden olan ciddi bir
performans maliyeti oluşturur.
Kullanıcı her hata yaptığında metnin titremesi veya kayması, korkunç bir kullanıcı deneyimi ( Bad UX ) yaratırdı.
Özellikle uzun metinlerde veya düşük performanslı cihazlarda bu durum, gecikme, donma ve input lag gibi sorunlara bile yol açabilir.
Bu yüzden tarayıcılar, düzeni yeniden hesaplamayı gerektiren ( Reflow ) tüm özellikleri yasaklar ve sadece "üzerine boyama" ( Repaint ) yapan özelliklere izin verir.
Yani ::spelling-error, DOM yapısını veya akış düzenini değiştirmez; sadece mevcut metnin üzerine eklenen bir görsel katman gibi çalışır.
Bu yaklaşım, hem performansı korur hem de kullanıcıya kesintisiz bir yazım deneyimi sunar.
Kısacası; burada amaç metni yeniden düzenlemek değil, hatayı bozmadan, akışı kesmeden ve dikkat dağıtmadan vurgulamaktır.
|
Dekorasyon Türü
|
Açıklama ve Örnekler
|
|---|---|
|
Gelişmiş Alt Çizgiler
Text Decoration
|
Sadece rengi değil, çizginin stilini de yönetebilirsiniz.
text-decoration-style:
dotted; ile
kelimenin altını nokta nokta çizebilir veya |
|
Arka Plan Vurgusu
Highlighter
|
Hatalı kelimeyi background-color: rgba(255, 255, 0, 0.3); gibi yarı saydam bir renkle boyayarak, sanki gerçek bir kağıt üzerinde fosforlu kalemle işaretlenmiş hissi verebilirsiniz. |
|
Metin Rengi ve Kontrast
Color
|
Hatalı kelimeyi color:
#ff0000;
yaparak kırmızıya boyayabilirsiniz.
|
|
Gölge İllüzyonu
Text Shadow
|
Font ağırlığını (font-weight)
değiştiremezsiniz,
ancak text-shadow kullanarak
kelimeye
"kalınlaşmış" veya "parlıyormuş" efekti
verebilirsiniz.
|
|
Senaryo
|
Neden Gerekli?
|
|---|---|
|
Hassas Arayüzler
|
Kullanıcının şiir yazdığı
veya yaratıcı metin oluşturduğu bir
uygulamada,
agresif kırmızı
çizgiler "ilham kırıcı"
olabilir.
|
|
Kod Editörleri
|
Web tabanlı kod editörlerinde,
değişken isimleri genellikle sözlükte
bulunmaz.
|
|
Erişilebilirlik (A11Y)
|
Bazı renk körlüğü türlerinde
kırmızı-yeşil ayrımı zordur.
|
Tetikleyici: Spellcheck Özelliği HTML Tarafındaki Anahtar
Tarayıcılar, performans ve kullanıcı deneyimi dengesini korumak için her alanda yazım denetimi yapmazlar.
Örneğin: Bir kullanıcı adı ( username ) veya e-posta alanı doldururken kırmızı çizgiler görmek rahatsız edicidir, çünkü bu alanlar genellikle sözlük dışı kelimeler içerir.
Bu yüzden tarayıcıların yerleşik bir "Niyet Okuma" protokolü vardır:
Eğer kısa bir input alanında ( "Mesaj Konusu" başlığı) CSS stilinizin çalışmasını istiyorsanız, tarayıcıyı buna zorlamanız gerekir.
Bunu yapmak için HTML elementine spellcheck="true" özelliğini açıkça eklemelisiniz.
Bu kod şu anlama gelir:
"Sevgili tarayıcı, burası kısa bir alan olsa da, kullanıcı buraya anlamlı bir cümle yazacak. Lütfen yazım denetimini aç."
Önemli Ayrım: CSS'in RolüBurada sıkça düşülen bir yanılgı vardır: CSS dosyanıza ::spelling-error kodunu eklemek, yazım denetimini başlatmaz.
CSS bir "Ressamdır", "Editör" değildir.
Editör ( Tarayıcı/İşletim Sistemi ) metni okur, hatayı bulur ve "Bak burada hata var" diye işaretler.
Ressam (CSS) ise sadece "Tamam, hata bulunduğuna göre ben bu kısmı kırmızıya boyuyorum" der ve hata bulunmazsa, CSS'in yapabileceği hiçbir şey yoktur.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Modern Taslak Defteri ( Blog Yazım Paneli )</title>
<link rel="stylesheet" href="style.css?v=1.0.150">
</head>
<body>
<div class="draft-container">
<div class="draft-badge">TASLAK MODU</div>
<div class="writing-zone" contenteditable="true" spellcheck="true">
Bura daki kelimelerden bazıları kasıtlı olarak yanliş yazılmıştır.
İnternet dünyasında hatasız yazmak zordur, ancak estetik hatalar yapmak mümkündür.
Lütfen bu alanı temizlemeyi denemeyin, sadece vurguları hissedin.
</div>
<div class="writing-footer">
<span>Karakter: 142</span>
<span>Okunabilirlik: Yüksek</span>
</div>
</div>
</body>
</html>
/* Genel Konteyner */
.draft-container {
background: #fff;
border-left: 5px solid #ff4757;
/* Hata rengine vurgu */
padding: 2rem;
border-radius: 4px 16px 16px 4px;
box-shadow: 10px 10px 30px rgba(0, 0, 0, 0.03);
font-family: 'Segoe UI', system-ui, sans-serif;
max-width: 650px;
margin: 20px auto;
}
.draft-badge {
font-size: 10px;
font-weight: bold;
letter-spacing: 1px;
color: #ff4757;
margin-bottom: 1rem;
}
.writing-zone {
font-size: 1.2rem;
line-height: 1.8;
color: #2f3542;
outline: none;
min-height: 120px;
}
.writing-footer {
margin-top: 1.5rem;
padding-top: 1rem;
border-top: 1px solid #f1f2f6;
display: flex;
justify-content: space-between;
font-size: 12px;
color: #a4b0be;
}
/* --- ANA ODAK: SPELLING ERROR ÖZELLEŞTİRME --- */
.writing-zone::spelling-error {
/* 1. Fosforlu Kalem Etkisi (Arka Plan) */
background-color: rgba(255, 71, 87, 0.15);
/* 2. Gelişmiş Alt Çizgi (Noktalı ve Kalın) */
text-decoration: underline dotted #ff4757;
text-decoration-thickness: 2px;
/* 3. Gölge İllüzyonu (Kelimeleri hafifçe dolgunlaştırır) */
text-shadow: 0.5px 0 0 #ff4757;
/* 4. Renk */
color: #ff4757;
}
/* Seçim yapıldığında (Vurgu ile karışmaması için) */
.writing-zone::selection {
background: #2f3542;
color: #fff;
}
CSS ::slotted() İçeriye Sızan Işık
Modern web geliştirmede, kendi özel HTML etiketlerimizi ( Custom Elements ) oluşturabiliyoruz. ( <benim-kartim> gibi ).
Bu yaklaşım, büyük projelerde tekrar kullanılabilir, kapsüllenmiş ve bağımsız çalışan bileşen mimarileri kurmamıza olanak tanır.
Bu bileşenler, dış dünyadan izole olmak için Shadow DOM kullanır.
Ancak bazen dışarıdan bu kartın içine bir başlık veya resim göndermemiz gerekir.
İşte bu noktada veri akışı iki yönlü bir yapı kazanır: bileşen hem dış dünyadan veri alır hem de kendi iç stil kurallarını korumaya çalışır.
HTML tarafında bu içerik aktarımını <slot> elementi yapar.
CSS tarafında ise, dışarıdan gelen bu "misafir" içeriği stilize etme yetkisi ::slotted() sözde elementindedir.
Bu yapı sayesinde, bileşen geliştiricisi hem iç düzeni kontrol eder hem de dışarıdan gelen içeriğin belirli kurallar dahilinde tutarlı görünmesini sağlayabilir.
Özellikle UI kütüphanelerinde ( kartlar, modal'lar, listeler ), slot yapısı sayesinde içerik tamamen esnek hale gelirken, stil bütünlüğü korunur.
Mantıksal Çelişki: Kimin Malı?Bir slot içine gönderilen element ( bir h1 etiketi gibi ), fiziksel olarak hala ana sayfada ( Light DOM ) yaşar, ancak görsel olarak bileşenin içinde ( Shadow DOM ) görüntülenir.
Bu durum, web geliştirmede sıkça karşılaşılan bir "aidiyet problemi" oluşturur: içerik kime ait?
Kod olarak dışarıda, görünüm olarak içeride olan bu elementler, klasik CSS seçicileri ile doğrudan kontrol edilemez.
::slotted(), bileşenin kendisine ait olmayan bu içeriğe "dokunabilmesini" sağlayan tek yasal yoldur.
Bu sayede geliştirici, dışarıdan gelen içeriği tamamen serbest bırakmak yerine, onu belirli bir tasarım sistemine uyacak şekilde yönlendirebilir.
Kısacası; ::slotted(), izolasyon ile esneklik arasında kurulan hassas dengenin bir aracıdır.
Seçicinin Sınırları ve "Düz Ağaç" Kuralı Neleri Seçebiliriz?
Bu kısıtlamayı anlamanın en kolay yolu, <slot> mekanizmasını bir "Hediye Kabul Noktası" gibi düşünmektir.
Kullanıcı ( Light DOM ), bileşeninize ( Shadow DOM ) bir hediye kutusu ( div ) verir.
Siz, ::slotted() kullanarak bu hediye kutusunun dışını kaplayabilir, kurdele takabilir veya rengini değiştirebilirsiniz.
Ancak kutunun içini açıp, içindeki eşyaları ( div etiketinin içindeki span, p veya img ) yeniden düzenleyemezsiniz ve kutu kapalıdır ve içindekiler gönderen kişinin sorumluluğundadır.
Teknik Engel: Flattened Tree (Düzleştirilmiş Ağaç)Tarayıcı sayfayı oluştururken, normal DOM ağacı ile Shadow DOM ağacını sanal olarak birleştirir ve buna "Düzleştirilmiş Ağaç" denir.
Bu düzleşme sırasında ::slotted() seçicisi, sadece slot'a doğrudan temas eden elementleri görecek şekilde programlanmıştır.
Yani CSS motoru, slot'tan içeri giren elementin "çocuklarına" bakmaz.
Bu yüzden ::slotted(div p) gibi, ebeveyn-çocuk ilişkisi kuran seçiciler ( combinators ) çalışmaz.
Kapsülleme (Encapsulation) İlkesiBu bir hata değil, bir güvenlik özelliğidir.
Eğer bileşeniniz, kullanıcının gönderdiği içeriğin en derin noktalarına kadar müdahale edebilseydi; kullanıcının kendi yazdığı stilleri istemeden bozabilirdiniz.
Web Bileşenleri standardı, "Bileşen sadece kendine ait olanı ve kendisine teslim edilen kutunun kabuğunu yönetmelidir." şeklinde ifade eder.
|
Kaynak
|
Öncelik Durumu
|
|---|---|
|
Light DOM (Sayfa CSS'i)
|
( Kazanan ) Element fiziksel olarak ana sayfada olduğu için, sayfanın genel CSS kuralları ( global styles ) en yüksek önceliğe sahiptir. |
|
::slotted() (Bileşen CSS'i)
|
( İkinci Öncelik ) Bileşen, içeriğe
"varsayılan" bir stil
önerebilir.
|
|
Browser Default
|
En düşük öncelik.
|
|
Senaryo
|
Çözüm ve Mantık
|
|---|---|
|
Tasarım Sistemleri (UI Kits)
|
Bir kart (<my-card>)
bileşeni
yaptığınızı
düşünün.
|
|
Düzen ve Geometri (Layout)
|
Bir liste bileşeni, içine
gelen her öğenin belirli bir genişlikte
olmasını
veya esnek kutu
( Flex Item ) gibi
davranmasını
gerektirebilir.
|
|
Medya Kontrolü
|
Kullanıcının bileşen içine
eklediği görsellerin ( img )
taşmasını önlemek için ::slotted(img) {
max-width: 100%;
} kuralı hayati önem taşır.
|
"Nazik" Stil (Polite Styling) Kavramı Bileşen vs. Kullanıcı İradesi
::slotted() kullanımının felsefi bir derinliği vardır, buna web literatüründe "Nazik Stil" denir.
Bu yaklaşımın temelinde, bileşen geliştiricisinin kontrol ile özgürlük arasında bir denge kurması yatar.
Yani amaç, kullanıcıya zorla bir tasarım dayatmak değil; onun işini kolaylaştıracak mantıklı ve estetik varsayılanlar sunmaktır.
Bileşen geliştiricisi olarak siz, ::slotted(button) ile bir buton stili tanımladığınızda, aslında şunu dersiniz:
"Eğer kullanıcı özel bir renk belirtmediyse, benim tasarladığım bu mavi rengi kullan."
Bu sayede bileşeniniz, kutudan çıktığı anda ( out-of-the-box ) tutarlı ve şık bir görünüm sunar.
Ancak bu stil, kesin bir kural değil; sadece bir öneri niteliğindedir.
Bu yaklaşım, özellikle tasarım sistemlerinde esneklik ve yeniden kullanılabilirlik açısından büyük avantaj sağlar.
Son Söz KullanıcınındırCSS öncelik kurallarına ( Specificity ) göre; kullanıcının ana sayfada ( Light DOM ) o elemente verdiği stil, her zaman sizin ::slotted() ile verdiğiniz stili ezer.
Bu durum, web platformunun en güçlü prensiplerinden biri olan kullanıcı kontrolü ilkesini korur.
Yani bileşeniniz ne kadar iyi tasarlanmış olursa olsun, son karar her zaman onu kullanan geliştiriciye aittir.
Bu harika bir özelliktir; çünkü bileşeniniz güzel bir varsayılan görünüm sunar, ancak kullanıcıyı kısıtlamaz ve özelleştirmeye ( customization ) izin verir.
Kısacası; iyi bir bileşen, sadece çalışan değil, aynı zamanda saygılı davranan bir bileşendir.
::slotted() ve ::part() yan yana
Slot’a düşen light DOM düğümü · shadow içindeki
part kapısı
<my-card><h2>Başlık</h2></my-card>
::slotted(h2) — slot’a doğrudan yerleşen
h2’ye nazik varsayılan stil (düşük özgüllük; sayfa
stilleri genelde üstün gelir).
Sınır: ::slotted() yalnızca slot’a atanmış
o üst düğümü seçer; onun içindeki torunları (ör. h2 span)
bu seçiciyle hedefleyemezsiniz.
my-card::part(icon) { color: red; }
part="icon" (veya boşlukla birden fazla isim)
taşıyan öğe — bileşen yazarının dış dünyaya açtığı kapı.
Koşul: ::part() seçicisi, shadow içinde
gerçekten part niteliği olan düğümlerle eşleşir; nitelik yoksa kural
uygulanmaz.
part ile işaretlenmiş, bilinçli
dışa açılan parçalara stil verir.
<!DOCTYPE html>
<html lang="tr">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>::slotted() - Shadow Demo</title>
<link rel="stylesheet" href="style.css?v=1.0.150">
</head>
<body>
<h1>::slotted() Demo - Nazik Stil vs Light DOM</h1>
<!-- ÖRNEK 1: Sadece bileşenin varsayılan stilleri (::slotted) çalışır -->
<benim-kartim>
<h2 class="slot-baslik">🎯 Bu başlık ::slotted(h2) ile turuncu oldu</h2>
<p>Bu paragraf ::slotted(p) ile arka plan ve kenar yumuşatma aldı.</p>
<button>Buton ::slotted(button) ile yeşil oldu</button>
</benim-kartim>
<hr>
<!-- ÖRNEK 2: Light DOM'dan gelen stiller ::slotted'u ezer -->
<benim-kartim>
<h2 class="slot-baslik" style="color: red;">🔴 Bu başlık: Light DOM inline style (kırmızı) → ::slotted ile verilen
turuncuyu ezer</h2>
<p style="background: white; border: 1px solid black;">Bu paragrafta inline style var → ::slotted geri planı
ezer</p>
<button style="background-color: gray; border-radius: 0;">Bu buton inline style ile gri → ::slotted yeşili
pasif</button>
</benim-kartim>
<hr>
<!-- ÖRNEK 3: Light DOM global CSS'inin önceliği göster -->
<benim-kartim>
<h2 class="slot-baslik">💜 Bu başlık: Light DOM global CSS (purple) → ::slotted turuncusunu ezer (Specificity
kazandı)</h2>
<button>Bu buton: Light DOM global CSS (gold) → ::slotted yeşilini ezer</button>
</benim-kartim>
<hr>
<div style="margin-top: 20px; padding: 12px; background: #f0f0f0; border-radius: 8px;">
<h3>📘 ::slotted() Özet Bilgi:</h3>
<ul>
<li>✅ <strong>Seçebildiği:</strong> Slot'a <strong>doğrudan</strong> yerleşen element (h2, p, button vs.)
</li>
<li>❌ <strong>Seçemediği:</strong> O elementin içindeki torunlar (h2 > span, p > strong)</li>
<li>🎯 <strong>Öncelik:</strong> Light DOM stilleri (global veya inline) > ::slotted() > tarayıcı
varsayılanı</li>
<li>💡 <strong>Felsefe:</strong> "Nazik Stil" - varsayılan öneri sunar, dayatmaz.</li>
<li>🔄 <strong>::part() ile farkı:</strong> ::part() shadow içindeki <strong>bilinçli açılmış</strong> özel
parçalara erişir. ::slotted() dışarıdan gelen doğrudan çocuğa erişir.</li>
</ul>
</div>
<script src="script.js?v=1.0.150"></script>
</body>
</html>
/* Bu stiller, bileşen içindeki slot içeriğine MÜDAHALE edebilir ve ::slotted()'u ezer */
benim-kartim .slot-baslik {
color: purple !important;
/* Kazanan stil - Light DOM üstün gelir */
font-style: italic;
}
/* Light DOM'dan global bir buton stili */
benim-kartim button {
background-color: gold;
border: 2px solid darkgoldenrod;
font-weight: bold;
}
// 2. CUSTOM ELEMENT tanımı (Shadow DOM içerir)
class BenimKartim extends HTMLElement {
constructor() {
super();
// Shadow DOM oluştur (kapalı/izole ortam)
const shadow = this.attachShadow({ mode: "open" });
// 3. SHADOW DOM STİLLERİ (Bileşenin iç stilleri)
shadow.innerHTML = `
<style>
/* Bileşenin kendi kabı */
.kart {
border: 2px solid #3498db;
border-radius: 12px;
padding: 16px;
background: #f9f9ff;
font-family: system-ui, sans-serif;
max-width: 400px;
margin: 20px 0;
}
.kart h3 {
margin-top: 0;
color: #2c3e50;
border-bottom: 2px solid #3498db;
padding-bottom: 8px;
}
/* ================================= */
/* 4. ::slotted() - NAZİK STİL (Polite Styling) */
/* ================================= */
/* Slot'a doğrudan yerleşen herhangi bir elementi hedefler */
::slotted(*) {
margin: 12px 0;
display: block;
}
/* Slot içindeki başlıklara varsayılan stil */
::slotted(h2) {
color: #e67e22;
font-size: 1.5rem;
font-weight: 600;
border-left: 4px solid #e67e22;
padding-left: 12px;
}
/* Slot içindeki butonlara varsayılan stil (nazik öneri) */
::slotted(button) {
background-color: #2ecc71;
color: white;
border: none;
padding: 8px 16px;
border-radius: 20px;
cursor: pointer;
font-size: 0.9rem;
transition: all 0.2s;
}
::slotted(button:hover) {
background-color: #27ae60;
transform: scale(1.02);
}
/* Slot içindeki paragraflara varsayan stil */
::slotted(p) {
color: #555;
line-height: 1.5;
background: #fff8e7;
padding: 8px;
border-radius: 8px;
}
/* ⚠️ ÖNEMLİ: Bu çalışmaz - ::slotted torunları seçemez */
/* ::slotted(p span) { color: red; } -> ÇALIŞMAZ! */
/* Bileşenin kendi slot etiketi */
slot {
display: block;
margin-top: 8px;
}
</style>
<div class="kart">
<h3>📦 Shadow Bileşenim</h3>
<div class="slot-alani">
<!-- İçerik buraya düşecek -->
<slot></slot>
</div>
<div style="font-size: 11px; color: #999; margin-top: 12px;">
⚡ ::slotted() nazik stil uyguluyor
</div>
</div>
`;
}
}
// Custom elementi kaydet
customElements.define("benim-kartim", BenimKartim);
CSS ::part() Kapalı Kutunun Anahtarı
Shadow DOM'un varoluş amacı Kapsülleme olayıdır.
Yani bileşenin içindeki stiller dışarı sızmaz, dışarıdaki stiller içeri giremez.
Bu izolasyon sayesinde bileşenler, tahmin edilebilir, güvenli ve çakışmasız bir şekilde çalışır.
Ancak bu "tam izolasyon" bazen bir dezavantaja dönüşebilir.
Çünkü gerçek dünyada geliştiriciler, kullandıkları bileşenleri tamamen olduğu gibi değil, projelerine uyacak şekilde özelleştirmek isterler.
Bir tasarımcı olarak, kullandığınız hazır bir "Video Player" bileşenin sadece "Oynat" butonunun rengini değiştirmek isteyebilirsiniz.
İşte tam bu noktada bir denge problemi ortaya çıkar: Bileşen tamamen kapalı kalırsa esneklik kaybolur, tamamen açık olursa kapsülleme anlamını yitirir.
::part(), bu iki uç arasında kurulan kontrollü bir köprü görevi görür.
Eskiden bu imkansızdı, bileşenin içine giremezdiniz, işte ::part(), bileşen yazarının size "Burayı boyayabilirsin" diye işaretlediği elementlere, Shadow DOM engelini aşarak ulaşmanızı sağlar.
Bu işaretleme genellikle HTML tarafında part attribute'u ile yapılır ve bu sayede bileşen, dış dünyaya küçük ama kontrollü bir stil API değeri sunmuş olur.
Yani ::part(), rastgele erişim değil; bilinçli olarak açılmış bir "özelleştirme kapısı" görevi görür.
Bu yaklaşım sayesinde hem bileşenin iç yapısı korunur, hem de geliştiriciye gerekli esneklik sağlanır.
Mantıksal Fark: Slotted vs Part::slotted() → Kullanıcının dışarıdan gönderdiği içeriği hedefler. ( İçerik kullanıcıya aittir ve bileşene sonradan eklenir ).
::part() → Bileşenin kendi sabit parçalarını hedefler. ( Parça bileşene aittir ve bileşenin iç yapısının bir parçasıdır ).
Bu farkı anlamak çok önemlidir; çünkü biri içeriği, diğeri ise yapıyı kontrol eder.
Kısacası; ::slotted() esnekliği temsil ederken, ::part() kontrollü erişimi temsil eder.
Sözleşme Tabanlı Stil (Contract) Attribute ve Pseudo Eşleşmesi
::part() büyüsünün çalışması için önce bileşen yazarının Shadow DOM içindeki elemente part="isim" özniteliğini eklemesi gerekir.
Bu işlem, aslında bileşenin dış dünyaya "kontrollü bir kapı açması" anlamına gelir.
Bu, yazılım mimarisindeki Public API ( Halka Açık Arayüz ) mantığıyla birebir aynıdır.
Geliştirici hangi parçaları dışarıya açacağına ( export ) karar verir, geri kalan her şey gizli ( private ) kalır.
Bu sayede bileşenin iç yapısı tamamen değiştirilebilir, ancak dışarıya sunulan sözleşme sabit kalır.
İyi tasarlanmış bir bileşen, hangi parçaların stilize edilebileceğini açıkça belirler ve bu parçaları anlamlı ve tutarlı isimlerle dışarıya açar.
Bu isimlendirme, sadece teknik değil aynı zamanda dokümantasyonun bir parçasıdır ve bileşenin nasıl kullanılacağını doğrudan etkiler.
CSS Tarafı: Tüketme (Consuming)Dış dünyadaki geliştirici, my-component::part(isim) seçicisini kullanarak, sanki o element normal DOM'daymış gibi stil yazabilir.
Bu kullanım, geliştiriciye hem güçlü bir kontrol sağlar hem de bileşenin iç yapısını bilmeden çalışabilme avantajı sunar.
Bu mekanizma sayesinde bileşenin iç yapısı değişse bile ( div yerine span kullanılsa bile ), part ismi aynı kaldığı sürece dışarıdaki CSS bozulmaz. Bu, sürdürülebilirliğin zirvesidir.
Bu yaklaşım, özellikle büyük projelerde ve ekip çalışmalarında kritik bir rol oynar; çünkü farklı geliştiriciler birbirinin kodunu kırmadan ilerleyebilir.
Aynı zamanda bu yapı, bileşenlerin versiyonlanabilir olmasını sağlar.
İç yapı değişse bile, dış API korunarak geriye dönük uyumluluk sağlanabilir.
Kısacası; ::part() sadece bir stil aracı değil, aynı zamanda bileşenler arası resmi bir iletişim protokolüdür.
|
Özellik
|
Detay
|
|---|---|
|
Pseudo-Class Zincirleme
|
::part(btn):hover veya ::part(input):focus gibi durum bildiren
sözde sınıfları
kullanabilirsiniz.
|
|
Yapısal Kısıtlama
|
::part(box) span gibi, part'ın
içindeki çocuklara erişemezsiniz.
|
|
Çoklu İsimlendirme
|
Bir elemente birden fazla rol
verebilirsiniz: part="tab
active".
|
İleri Seviye: Part Forwarding İç İçe Bileşenlerde Erişim
Eğer <user-card> bileşeni içinde başka bir bileşen olan <custom-button> kullanıyorsa, dışarıdaki stil dosyası ::part ile sadece en dıştaki katmana erişebilir.
Bunun nedeni, her bileşenin kendi Shadow DOM sınırına sahip olması ve bu sınırların varsayılan olarak birbirinden izole çalışmasıdır.
Bu yapı, iç içe geçmiş bileşenlerde bir katmanlı mimari oluşturur ve her katman kendi kontrol alanını korur.
Ancak bu izolasyon, derindeki bileşenlere erişimi zorlaştırır ve doğrudan stil vermeyi imkansız hale getirir.
Derindeki butonun "part"ını dış dünyaya açmak için, ara katmandaki bileşenin bu parçayı "Yönlendirmesi" gerekir.
Bu, aslında bileşenler arasında bir yetki devri anlamına gelir.
Bu işlem exportparts özelliği ile yapılır ve ara katman, alt bileşenin belirli parçalarını dış dünyaya yeniden expose eder.
Bu sayede, çok katmanlı karmaşık sistemlerde bile, en tepeden en alttaki butonun rengini değiştirmek mümkün hale gelir.
Bu yapı özellikle büyük UI sistemlerinde, bileşenler arası stil akışını kontrollü bir şekilde zincirleme olarak ilerletmeyi sağlar.
Sonuç: Temalanabilirlik (Theming)::part(), modern web bileşen kütüphanelerinin ( Shoelace, Ionic , vb.) tema sistemlerinin bel kemiğidir.
Bu yapı sayesinde bileşenler, sabit tasarımlar yerine tema ile şekillenen dinamik yapılara dönüşür.
Geliştiriciye, bileşenin kaynak kodunu değiştirmeden ( No-Code / Low-Code mantığına yakın ), sadece CSS yazarak bileşeni tamamen özelleştirme özgürlüğü sunar.
Bu yaklaşım, tasarım sistemlerinde global tema yönetimi uygulamayı da oldukça kolaylaştırır.
Kısacası; ::part() ve exportparts birlikte çalışarak, kapalı bileşen dünyasında bile esnek ve ölçeklenebilir bir stil mimarisi kurmanızı sağlar.
<!DOCTYPE html>
<html lang="tr">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>::part() Demo - Shadow DOM Kapıları</title>
<link rel="stylesheet" href="style.css?v=1.0.150">
</head>
<body>
<h1>🎯 <code>::part()</code> - Shadow DOM yapısının Kapıları</h1>
<p><code>::part()</code> ile bileşenin içindeki <strong>kontrollü alanlara</strong> dışarıdan stil verebilirsiniz.
</p>
<!-- ÖRNEK 1: Varsayılan bileşen -->
<h3>📦 Örnek 1: ::part() ile özelleştirilmiş bileşen</h3>
<ozel-kart></ozel-kart>
<!-- ÖRNEK 2: Farklı tema uygulanmış bileşen -->
<h3>🎨 Örnek 2: Dark tema (Light DOM CSS ile)</h3>
<div class="theme-dark">
<ozel-kart></ozel-kart>
</div>
<!-- ÖRNEK 3: Aynı sayfada birden fazla bileşen -->
<h3>🔄 Örnek 3: Aynı bileşen, farklı stiller</h3>
<ozel-kart style="display: inline-block; margin-right: 20px;"></ozel-kart>
<ozel-kart style="display: inline-block;"></ozel-kart>
<hr style="margin: 40px 0;">
<!-- BİLGİ KUTUSU -->
<div style="background: #f0f4f8; padding: 20px; border-radius: 16px; font-family: monospace;">
<h3>📘 ::part() Bilgi Kartı</h3>
<ul style="line-height: 1.8;">
<li>✅ <strong>Seçebildiği:</strong> <code>part="isim"</code> ile işaretlenmiş <strong>herhangi bir
element</strong></li>
<li>✅ <strong>Pseudo-class zincirleme:</strong> <code>::part(btn):hover</code>,
<code>::part(input):focus</code> ✅
</li>
<li>❌ <strong>Seçemediği:</strong> Part içindeki çocuk elementler (<code>::part(box) span</code> ❌)</li>
<li>✅ <strong>Çoklu isim:</strong> <code>part="button primary"</code> şeklinde kullanılabilir</li>
<li>🔗 <strong>İleri seviye:</strong> İç içe bileşenler için <code>exportparts</code> kullanılır</li>
<li>🎯 <strong>::slotted() farkı:</strong> <code>::slotted()</code> dışarıdan GELEN içeriğe stil verir,
<code>::part()</code> bileşenin KENDİ parçasına stil verir
</li>
</ul>
</div>
<div
style="margin-top: 20px; padding: 16px; background: #fff3cd; border-left: 4px solid #ffc107; border-radius: 8px;">
<strong>💡 Önemli:</strong> Bu örnekte <code>part="icon"</code>, <code>part="card-header"</code>,
<code>part="card-body"</code>,
<code>part="badge"</code> ve <code>part="submit-btn"</code> olmak üzere <strong>5 farklı kapı</strong>
açılmıştır.
Her birine Light DOM'dan <code>ozel-kart::part(isim)</code> ile müdahale edebilirsiniz.
</div>
<script src="script.js?v=1.0.150"></script>
</body>
</html>
/* Bileşenin part="submit-btn" olan kısmını hedefle */
ozel-kart::part(submit-btn) {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
border: none;
padding: 12px 28px;
font-size: 1rem;
font-weight: bold;
border-radius: 50px;
color: white;
cursor: pointer;
transition: transform 0.2s, box-shadow 0.2s;
}
/* Hover durumunda pseudo-class zincirleme - MÜTHİŞ ÖZELLİK! */
ozel-kart::part(submit-btn):hover {
transform: translateY(-2px);
box-shadow: 0 10px 20px rgba(102, 126, 234, 0.3);
}
/* Aktif (tıklanma) durumu */
ozel-kart::part(submit-btn):active {
transform: translateY(1px);
}
/* part="icon" hedefleme */
ozel-kart::part(icon) {
width: 24px;
height: 24px;
fill: #ff6b6b;
transition: fill 0.2s, transform 0.2s;
vertical-align: middle;
margin-right: 8px;
}
/* Icon hover efekti */
ozel-kart::part(icon):hover {
fill: #ee5a24;
transform: scale(1.1);
}
/* part="card-header" hedefleme */
ozel-kart::part(card-header) {
font-size: 1.8rem;
font-weight: 800;
background: linear-gradient(135deg, #667eea, #764ba2);
-webkit-background-clip: text;
background-clip: text;
color: transparent;
border-left: 4px solid #764ba2;
padding-left: 16px;
}
/* part="card-body" içeriğini stilize et */
ozel-kart::part(card-body) {
font-size: 1rem;
line-height: 1.6;
color: #2d3748;
background: #f7fafc;
padding: 16px;
border-radius: 12px;
}
/* part="badge" özelleştirme */
ozel-kart::part(badge) {
background: #48bb78;
color: white;
padding: 4px 12px;
border-radius: 20px;
font-size: 0.75rem;
font-weight: 600;
display: inline-block;
}
/* ⚠️ Bu ÇALIŞMAZ - part içindeki çocuklara erişilemez */
/* ozel-kart::part(card-body) span { color: red; } -> ÇALIŞMAZ! */
/* Aynı anda birden fazla bileşeni hedefleme */
.theme-dark::part(card-header) {
background: linear-gradient(135deg, #f093fb, #f5576c);
-webkit-background-clip: text;
background-clip: text;
}
.theme-dark::part(card-body) {
background: #2d3748;
color: #e2e8f0;
}
.theme-dark::part(submit-btn) {
background: linear-gradient(135deg, #f093fb, #f5576c);
}
class OzelKart extends HTMLElement {
constructor() {
super();
const shadow = this.attachShadow({ mode: "open" });
// Bileşenin iç yapısı - part attribute'ları ile kapılar açılıyor
shadow.innerHTML = `
<style>
/* Shadow DOM iç stilleri - varsayılan görünüm */
.kart {
border: 2px solid #e2e8f0;
border-radius: 20px;
padding: 20px;
background: white;
font-family: system-ui, -apple-system, sans-serif;
max-width: 450px;
margin: 20px 0;
transition: all 0.3s;
}
/* Shadow içinde varsayılan stiller (dışarıdaki ::part bunları ezer) */
.kart-header {
font-size: 1.5rem;
font-weight: 600;
margin-bottom: 12px;
color: #2d3748;
}
.kart-body {
margin: 16px 0;
color: #4a5568;
}
.btn {
background: #cbd5e0;
border: none;
padding: 10px 24px;
border-radius: 8px;
cursor: pointer;
font-weight: 500;
transition: all 0.2s;
}
.icon-svg {
width: 20px;
height: 20px;
fill: #a0aec0;
}
.badge {
background: #e2e8f0;
color: #4a5568;
padding: 2px 8px;
border-radius: 12px;
font-size: 0.7rem;
}
.flex-row {
display: flex;
align-items: center;
justify-content: space-between;
margin-top: 16px;
}
</style>
<div class="kart">
<div class="flex-row">
<!-- PART İLE AÇILAN KAPILAR - Dış dünyaya kontrollü erişim -->
<div part="card-header" class="kart-header">
<svg part="icon" class="icon-svg" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24">
<path d="M12 2L15 8.5L22 9.5L17 14L18.5 21L12 17.5L5.5 21L7 14L2 9.5L9 8.5L12 2Z" fill="currentColor"/>
</svg>
Hoş Geldiniz
</div>
<span part="badge" class="badge">YENİ</span>
</div>
<div part="card-body" class="kart-body">
Bu bir Shadow DOM bileşenidir. <strong>part="..."</strong> attribute'u ile işaretlenen alanlar,
dış dünyaya kontrollü bir şekilde açılmıştır.
</div>
<button part="submit-btn" class="btn">✨ Keşfet</button>
</div>
`;
}
}
customElements.define("ozel-kart", OzelKart);
CSS ::-webkit-scrollbar Sistemi Başlatan Anahtar
Bir web sayfasında aşağı indiğinizde sağda beliren gri çubuk, aslında sitenize ait değildir; o, kullanıcının İşletim Sisteminin
(Windows, macOS , Android) bir parçasıdır.
Bu çubuk, tarayıcı tarafından render edilse bile, görünümünü büyük ölçüde işletim sistemi ve kullanıcı ayarları belirler.
Bu yüzden her bilgisayarda farklı görünür. ::-webkit-scrollbar, bu dış bağımlılığı kesip atmanızı ve kontrolü tamamen CSS'e almanızı sağlar.
Bu seçiciyi yazdığınız an, tarayıcı varsayılan çubuğu yok eder ve sizin talimatlarınızı bekleyen boş bir tuval oluşturur.
Artık scrollbar, sadece bir sistem bileşeni değil; sitenizin tasarım dilinin bir parçası haline gelir.
Özellikle modern arayüzlerde, scrollbar bile renk, kalınlık ve etkileşim hissi açısından marka kimliğini yansıtan bir unsur olarak kullanılabilir.
Ancak bu güç beraberinde sorumluluk da getirir; çünkü yanlış tasarlanmış bir scrollbar, kullanılabilirliği ciddi şekilde düşürebilir.
Kritik Uyarı: Standart Dışı Yapıİsmindeki -webkit- ön eki, bunun bir W3C standardı olmadığını gösterir.
Yani bu özellik, tüm tarayıcılarda aynı şekilde çalışacağı garanti edilen bir yapı değildir.
Destekleyenler: Chrome, Edge, Safari, Opera ve tüm Chromium tabanlı tarayıcılar ( Dünya genelinin %80+'i ).
Bu geniş destek oranı, pratikte bu özelliği oldukça kullanılabilir kılar; ancak yine de evrensel değildir.
Desteklemeyenler: Firefox (Firefox'un kendine has, daha kısıtlı bir scrollbar-color standardı vardır).
Bu nedenle en doğru yaklaşım, scrollbar stilini geliştirme katmanı olarak görmek ve kritik kullanıcı deneyimini buna bağımlı hale getirmemektir.
Kısacası; ::-webkit-scrollbar, güçlü ama dikkatli kullanılması gereken bir araçtır: kontrol sizde, ama uyumluluk her zaman garanti değildir.
Dikey scrollbar anatomisi ::-webkit-scrollbar ailesi (WebKit / Chromium)
Boyutlandırma ve Aktivasyon Görünmezlikten Varlığa
::-webkit-scrollbar seçicisine bir genişlik ( width ) veya yükseklik ( height ) vermezseniz, kaydırma çubuğu görünmez, çünkü varsayılanı "sıfır" boyutundadır bu ailenin en önemli kuralından biridir.
Diğer parçaları ( thumb, track ) ne kadar boyarsanız boyayın, ana konteynerin boyutu yoksa ekrana çizilmezler.
Bu durum, scrollbar sisteminin bir kapsayıcı mantığıyla çalıştığını gösterir: önce alan tanımlanır, sonra iç parçalar render edilir.
Yani ::-webkit-scrollbar, aslında tüm alt parçaların var olabilmesi için gerekli olan temel iskelet yapısıdır.
Eğer bu iskelet oluşturulmazsa, alt parçalar teknik olarak tanımlanmış olsa bile kullanıcı tarafından hiçbir zaman görülmez.
width: Dikey (Vertical) scrollbar'ın kalınlığını belirler.
height: Yatay (Horizontal) scrollbar'ın kalınlığını belirler.
Bu değerler sadece görsel bir tercih değil, aynı zamanda kullanılabilirlik açısından da kritik öneme sahiptir.
Çok ince scrollbar'lar estetik görünebilir ancak özellikle dokunmatik cihazlarda veya düşük hassasiyetli inputlarda etkileşimi zorlaştırabilir.
Buna karşılık çok kalın scrollbar'lar da içerik alanını daraltarak gereksiz bir görsel yük oluşturabilir.
Bu yüzden ideal yaklaşım, tasarım ile kullanılabilirlik arasında denge kurmaktır.
Kısacası; scrollbar'ı görünür yapmak sadece bir başlangıçtır, asıl önemli olan onu doğru boyutta ve doğru bağlamda sunmaktır.
|
CSS Özelliği
|
scrollbar
|
track
|
thumb
|
button
|
|---|---|---|---|---|
|
background-color
|
|
|
|
|
|
background-image
(gradient, pattern)
|
|
|
|
|
|
border-radius
|
(kısıtlı)
|
|
|
|
|
box-shadow
|
|
|
|
|
|
:hover
pseudo-class
|
|
|
|
|
|
:active
pseudo-class
|
|
|
|
|
|
CSS Seçici
|
Etki Alanı
|
Kullanım Amacı
|
|---|---|---|
|
::-webkit-scrollbar
(global seçici)
|
Global
Tüm belgeyi etkiler |
Tema/Tasarım Sistemi Tüm sayfada tutarlı scrollbar |
|
.element::-webkit-scrollbar
Örnek: .chat, .modal
|
Lokal
Sadece hedeflenen element |
Özel Bileşenler Chat, modal, sidebar gibi |
|
body::-webkit-scrollbar
(body elementi)
|
Spesifik
Sadece body elementi |
Sayfa Scrollbar'ı Ana pencere scrollbar özelleştirme |
|
*::-webkit-scrollbar
(evrensel seçici)
|
Tüm Elementler
Her kaydırılabilir element |
Radikal Tema Performans riski (nadiren kullanılır) |
Mobil Cihaz Paradoksu Dokunmatik Ekranlar ve Kaybolan Çubuklar
iOS ve Android gibi modern mobil işletim sistemleri, ekran alanından çalmamak için kaydırma çubuklarını varsayılan olarak gizler ve sadece kaydırma anında gösterir ( Auto-hiding ).
Bu yaklaşım, mobil cihazlarda maksimum içerik alanı sağlamak için tasarlanmış bir alan optimizasyonu stratejisidir.
Ayrıca dokunmatik ekranlarda kullanıcı, scroll işlemini doğrudan içerik üzerinde parmak hareketiyle yaptığı için, görsel bir scrollbar'a olan ihtiyaç masaüstüne göre çok daha düşüktür.
Bu nedenle scrollbar, mobilde bir kontrol elemanından ziyade geçici bir geri bildirim aracı gibi davranır.
Eğer ::-webkit-scrollbar ile özel bir stil tanımlarsanız, bu "otomatik gizlenme" özelliğini bozabilir ve çubuğu kalıcı olarak ekranda tutabilirsiniz.
Bu durum, mobil tasarımda istenmeyen bir darlık yaratabilir ve kullanıcı deneyimini olumsuz etkileyebilir.
Özellikle küçük ekranlarda, sürekli görünen bir scrollbar içerik alanını daraltır ve görsel karmaşaya neden olabilir.
Ayrıca bazı mobil tarayıcılarda bu tür özelleştirmeler, performans açısından da beklenmeyen sonuçlar doğurabilir.
Bu nedenle genellikle @media (hover: hover) sorgusu ile sadece faresi olan cihazlarda ( masaüstü ) bu özelleştirmenin yapılması önerilir.
Alternatif olarak @media (pointer: fine) gibi sorgular kullanılarak daha hassas kontrol senaryoları da oluşturulabilir.
Kısacası; mobilde scrollbar tasarımı yapmak yerine, çoğu zaman en iyi tasarım kararı hiç dokunmamaktır.
Kaydırma Yolu (Track) ::-webkit-scrollbar-track
Bu seçici, kaydırma çubuğunun sabit ve hareketsiz arka planını temsil eder. Tutamaç (Thumb) bu rayın üzerinde hareket eder.
Bu yapı, fiziksel dünyadaki bir ray sistemi gibi düşünülebilir; track yönü belirler, thumb ise bu yol üzerinde ilerler.
Track, sadece boş bir zemin değildir; modern arayüzlerde sayfa içeriği ile scrollbar arasında "nefes aldıran" bir tampon bölge görevi görür.
Aynı zamanda kullanıcıya scroll edilebilir alanın sınırlarını gösteren pasif bir rehber olarak çalışır.
Bu nedenle track tasarımı, doğrudan fark edilmese bile genel kullanıcı deneyimini arka planda yönlendiren önemli bir unsurdur.
Tasarım İpucu: Derinlik AlgısıYukarıdaki tabloda bahsettiğimiz Inset Shadow (İç Gölge), profesyonel UI tasarımlarının sırrıdır.
Düz bir renk yerine
box-shadow: inset 0 0 5px rgba(0,0,0,0.2); kullanmak, scrollbar'ın sayfanın
"üzerinde" değil
"içinde" olduğu hissini yaratır.
Bu küçük dokunuş, arayüze derinlik, katman ve fiziksel gerçeklik hissi kazandırır.
Özellikle düz (flat) tasarımlarda bu tür ince detaylar, bileşenin daha profesyonel ve "tamamlanmış" görünmesini sağlar.
Track Etkileşimsizdir : Neden Hover Çalışmaz?::-webkit-scrollbar-track etkileşimsel bir element değildir.
Bu element üzerinde :hover, :active veya :focus pseudo-class'ları tarayıcılar tarafından desteklenmez veya tutarsız çalışır.
Bunun teknik nedeni, track'in sadece bir "zemin" veya "ray" olması, kullanıcıdan bir girdi beklemeyen dekoratif bir katman olarak tasarlanmasıdır.
Track, etkileşim değil referans sağlar; yani kullanıcıya nerede olduğunu gösterir ama onunla doğrudan iletişime girmez.
Etkileşim ( renk değişimi, büyüme vb.) sadece hareketli parça olan ::-webkit-scrollbar-thumb üzerinde çalışır.
Bu ayrım, kullanıcı deneyiminde net bir rol dağılımı sağlar: track yön gösterir, thumb ise kontrol sağlar.
|
Özellik Grubu
|
Kullanım ve Etkisi
|
|---|---|
|
Arka Plan (Background)
|
Sadece renk (background-color)
değil, desenler
veya gradient geçişleri ( linear-gradient
)
kullanılabilir.
|
|
Derinlik (Shadows)
|
box-shadow: inset ... en popüler
tekniktir.
|
|
Yuvarlatma (Radius)
|
border-radius ile rayın uçlarını
ovalleştirebilirsiniz.
|
|
Sınırlar (Borders)
|
Track etrafına ince bir çizgi çekerek
onu içerikten net bir şekilde
ayırabilirsiniz.
|
|
Strateji
|
Kod Örneği
|
Sonuç Görünüm
|
|---|---|---|
|
Dikey Boşluk (Margin)
|
margin: 4px 0;
|
Ray, konteynerin üst ve alt
kenarlarına yapışmaz.
|
|
Yatay Boşluk (Margin)
|
margin: 0 4px;
|
Yatay çubuk, sol ve sağ kenarlardan içeri çekilerek "havada asılı" etkisi yaratır. |
|
Minimal Tasarım
|
background: transparent;
(track gizlenir)
|
Sadece thumb görünür, track saydamdır.
|
Kaydırma Tutamacı (Thumb) ::-webkit-scrollbar-thumb
Scrollbar sisteminin kalbi burasıdır. Kullanıcının mouse ile tutup aşağı-yukarı sürüklediği, sayfanın neresinde olduğunu gösteren hareketli parçadır.
Track (zemin) pasif bir rehber iken, ::-webkit-scrollbar-thumb doğrudan kontrol sağlayan aktif bileşendir.
Bu nedenle thumb, kullanıcı ile scrollbar arasındaki birincil etkileşim noktasıdır ve tasarımda en fazla dikkat edilmesi gereken parçadır.
Tasarım açısından en özgür olduğunuz alandır; çünkü burası etkileşimsel bir öğedir ve kullanıcıyla doğrudan iletişim kurar.
Bu yüzden thumb tasarımında sadece estetik değil, erişilebilirlik ve kullanılabilirlik de ön planda tutulmalıdır.
Scrollbar genişliğini width: 12px yapsanız bile, tutamacı daha ince ( 8px gibi ) göstermek isteyebilirsiniz.
Bunu yapmanın en temiz yolu, thumb'a şeffaf bir kenarlık ( border ) vermek ve background-clip: content-box kullanmaktır.
Bu teknik sayesinde, fiziksel alan korunurken görsel alan küçültülür ve daha zarif bir görünüm elde edilir.
Aynı zamanda bu yöntem, kullanıcıya fark ettirmeden daha geniş bir tıklanabilir alan sunar.
Çok uzun sayfalarda thumb, bir nokta kadar küçülebilir ve tutması imkansız hale gelir.
Bu durum, özellikle masaüstü kullanımda ciddi bir erişilebilirlik problemi oluşturur.
Bunu önlemek için her zaman min-height özelliği kullanılmalıdır. ( min-height: 40px; )
Bu değer, kullanıcıya her zaman tutulabilir bir alan garanti eder ve deneyimi stabil tutar.
Otomatik Boyutlandırma: Viewport/Content OranıThumb'un yüksekliği (veya genişliği yatayda) otomatik hesaplanır:
Formül: Thumb boyutu = (Görünür alan / Toplam içerik) × Scrollbar uzunluğu
Bu hesaplama, kullanıcıya sayfa içinde bulunduğu konumu görsel olarak anlatan bir oran göstergesi görevi görür.
İçerik ne kadar uzunsa thumb o kadar küçülür; içerik kısaldıkça thumb büyür.
Bu demektir ki, CSS ile height veya width veremezsiniz, sadece min-height/min-width ile asgari boyutu garanti edebilirsiniz.
Kısacası; thumb tasarımı, sadece bir stil meselesi değil, aynı zamanda kullanıcının navigasyon deneyimini doğrudan etkileyen bir faktördür.
|
Stil Aracı
|
Kullanım Amacı
|
|---|---|
|
background-color
|
Tutamaç rengi.
|
|
background-image
|
Gradient veya desenler.
|
|
border-radius
|
En kritik özelliktir.
|
border
|
İpucu: Şeffaf bir
border kullanarak, tutamacı
kenarlardan "küçültmüş"
gibi gösterebilirsiniz
|
|
box-shadow
|
Gölge efekti.
|
|
transform (sınırlı)
|
scale() ile hover anında büyütme efekti.
|
|
Durum (State)
|
Kod Örneği
|
Görsel Efekt
|
|---|---|---|
|
Varsayılan
|
background: #ccc;
|
Sakin, dikkat çekmeyen gri ton. |
|
:hover
|
background: #888;
|
Mouse üzerine gelince koyulaşır, "beni tutabilirsin" mesajı verir. |
|
:hover + transform
|
transform: scale(1.05);
|
Hafif büyüme efekti. "Canlılık" hissi katar. |
|
:active
|
background: #555;
|
Tıklayıp sürüklerken en koyu rengi
alır.
|
|
:active + shadow
|
box-shadow: 0 0 8px rgba(0,0,0,0.3);
|
Tıklanınca gölge belirir.
|
Yön Butonları (Buttons) ::-webkit-scrollbar-button
Kaydırma çubuğunun (Track) başlangıç ve bitiş noktalarında yer alan, tıklandığında içeriği küçük adımlarla kaydıran butonlardır.
Track yönü belirler, thumb konumu gösterir; bu butonlar ise adım adım navigasyon sağlar.
Bu yapı, özellikle hassas kaydırma gereken durumlarda ( uzun listeler, kod editörleri veri tabloları ) kullanıcıya ekstra kontrol sunar.
Varsayılan olarak Windows işletim sisteminde "Yukarı/Aşağı Ok" olarak görünürken, macOS ve modern mobil tasarımlarda genellikle gizlidir.
Bunun nedeni, modern UI yaklaşımında bu butonların gereksiz görsel yük olarak değerlendirilmesi ve kullanıcıların doğrudan scroll
( wheel / touch ) kullanmaya alışmış olmasıdır.
Bu seçici, o okları geri getirmenizi, şeklini değiştirmenizi veya tamamen yok etmenizi sağlar.
Ancak pratikte çoğu modern projede bu butonlar ya tamamen gizlenir ya da minimal bir şekilde stilize edilir.
Kritik Mantık: Increment ve DecrementBu butonları stillendirirken en çok karıştırılan nokta yönlerdir.
CSS, "Yukarı/Aşağı" demez; matematiksel bir mantık kullanır:
Azaltan ( :decrement ) Değeri azaltan yöndür ve dikeyde "Yukarı", Yatayda "Sol" anlamına gelir. ( Başlangıç noktası ).
Artıran ( :increment ) Değeri artıran yöndür ve dikeyde "Aşağı", Yatayda "Sağ" anlamına gelir. ( Bitiş noktası ).
Bu mantık, scrollbar'ın yönünden bağımsız olarak tutarlı bir sistem sunar ve hem yatay hem dikey kullanımda aynı şekilde çalışır.
Görünmezlik Sorunu ve Çözümü::-webkit-scrollbar-button seçicisini yazdığınızda ekranda hiçbir şey göremeyebilirsiniz.
Çünkü bu butonlar varsayılan olarak boş bir kutudur; tarayıcı yalnızca alanı oluşturur, içeriği sizin sağlamanızı bekler.
Onları görünür kılmak için ya background-color vermeli ya da bir
background-image (genellikle ok ikonu) atamalısınız.
Ayrıca background-size ve background-position gibi özelliklerle ikonun hizalaması doğru yapılmalıdır.
Kısacası; bu butonlar güçlü bir kontrol aracı olsa da, modern arayüzlerde çoğu zaman opsiyonel ve nadiren kullanılan bir bileşen haline gelmiştir.
|
Seçici Kombinasyonu
|
Hedeflediği Buton
|
|---|---|
|
::-webkit-scrollbar-button
|
Tüm yönlerdeki ( yukarı, aşağı, sağ, sol ) butonların hepsini aynı anda seçer. |
|
:vertical:decrement
|
Dikey çubuğun En Üstündeki ( Yukarı Ok ) butonu. |
|
:vertical:increment
|
Dikey çubuğun En Altındaki ( Aşağı Ok ) butonu. |
|
:horizontal:decrement
|
Yatay çubuğun En Solundaki ( Sol Ok ) butonu. |
|
:horizontal:increment
|
Yatay çubuğun En Sağındaki ( Sağ Ok ) butonu. |
|
Teknik
|
Açıklama
|
|---|---|
|
Blok Boyama
|
Basitçe background-color: red; diyerek buton
alanını
boyarsınız.
|
|
Resim/SVG Kullanımı
|
En yaygın yöntemdir.
|
|
Gizleme (Modern Stil)
|
Modern arayüzlerde buton istenmez. display: none; veya height: 0; verilerek butonlar tamamen kaldırılır. |
Köşe Alanı (Corner) ::-webkit-scrollbar-corner
Bir elementte hem dikey hem de yatay kaydırma çubuğu aktif olduğunda, bu iki çubuğun kesiştiği sağ-alt köşesinde oluşan küçük kare alandır.
Bu alan, scrollbar sisteminin en küçük ama en kritik bağlantı noktasıdır; çünkü iki farklı ekseni görsel olarak birleştirir.
Track yönü belirler, thumb hareket eder, butonlar navigasyon sağlar; corner ise bu sistemin tamamlayıcı boşluğunu doldurur.
Varsayılan olarak genellikle gri veya sayfa arka plan rengiyle aynıdır ve çoğu tasarımcı tarafından fark edilmez.
Ancak özel scrollbar tasarımlarında, bu köşe boşluğu taslak hatası veya renk uyumsuzluğu yaratabilir.
Bu durum özellikle koyu tema, gradient arka planlar veya cam efekti (glassmorphism) kullanılan arayüzlerde daha belirgin hale gelir.
Kritik Not: Çift Scrollbar GerekliliğiBu seçici sadece ve sadece hem dikey hem yatay scrollbar'ın aynı anda görünür olduğu durumlarda etkilidir.
Bu durum genellikle büyük veri tablolarında, kod editörlerinde veya sabit boyutlu container'larda ortaya çıkar.
Eğer elementinizde sadece dikey veya sadece yatay kaydırma varsa, bu köşe alanı oluşmaz ve stil vermeniz hiçbir etki göstermez.
Bu yüzden bu pseudo-element, her projede değil, spesifik senaryolarda anlam kazanır.
Tasarım Problemi: Renk UyumsuzluğuEn yaygın sorun, track ve thumb'ı özelleştirdiğinizde köşenin varsayılan gri renginde kalmasıdır.
Bu durum, scrollbar'ın geri kalanıyla görsel olarak kopuk bir parça oluşturur.
Örneğin koyu tema bir uygulamada (#222 rengi) açık gri scrollbar yaptıysanız, gri köşe göz tırmalayan bir nokta olarak kalır.
Bu küçük detay, kullanıcı fark etmese bile arayüzün profesyonellik algısını doğrudan etkiler.
Son Söz: Gereksiz mi, Gerekli mi?::-webkit-scrollbar-corner genellikle "over-engineering" (gereksiz karmaşıklık) olarak görülür.
Ancak bu, sadece yüzeysel bir bakış açısıdır; çünkü modern UI'da detaylar, bütün algıyı belirler.
Premium UI tasarımlarında ve koyu/açık tema geçişlerinde, bu küçük detay profesyonellik ile amatörlük arasındaki farkı yaratır.
Kural: Eğer track'e özel bir arka plan verdiyseniz, köşeyi de mutlaka stilleyin veya transparent yapın.
Kısacası; corner küçük bir detaydır ama doğru kullanıldığında arayüzün tamamlanmış ve tutarlı görünmesini sağlar.
|
Senaryo
|
Görünüm ve Durum
|
|---|---|
|
Geniş Tablolar
|
Excel benzeri geniş tablolarda hem
yatay hem dikey kaydırma aktif olur.
|
|
Kod Editörleri
|
Uzun kod satırları yatay, çok sayıda
satır dikey scroll gerektirir.
|
|
Responsive Tasarım
|
Küçük ekranlarda içerik sığmadığında
çift scrollbar oluşur.
|
|
Resim Galerileri
|
Hem yatayda resim sıralaması hem dikeyde kategori listesi olduğunda köşe belirginleşir. |
|
Teknik
|
CSS Kodu
|
Etkisi
|
|---|---|---|
|
Renk Eşleştirme
|
background: #f0f0f0; |
Köşeyi track rengiyle aynı yapar.
|
|
Saydam Yapma
(transparent)
|
background: transparent; |
Köşeyi tamamen gizler.
|
|
Gradient Köşe
|
background: linear-gradient(135deg, #f0f0f0, #e0e0e0); |
Köşeye derinlik hissi verir.
|
|
Köşe Simgesi
(advanced)
|
background: url('corner-icon.svg') center no-repeat; |
Çok nadir kullanılır.
|
Yol Parçaları (Track Pieces) ::-webkit-scrollbar-track-piece
Bu seçici, kaydırma yolunu ( track ) iki ana parçaya bölmenizi sağlar: thumb'un üstünde/ötesinde kalan alanlar.
Standart ::-webkit-scrollbar-track tüm yolu tek parça olarak ele alırken, bu seçici ile thumb'un öncesi ve sonrasını ayrı ayrı stillendirebilirsiniz.
Bu yaklaşım, scrollbar'ı pasif bir bileşen olmaktan çıkarıp durum bilgisi veren aktif bir görsel araca dönüştürür.
Özellikle "progress bar" benzeri efektler veya "okuyucu modu" göstergeleri için idealdir.
Örneğin: Kullanıcı sayfanın %60'ındaysa, thumb'un üstündeki track-piece farklı bir renkle boyanarak okuma ilerlemesi görselleştirilebilir.
Bu teknik, özellikle bloglar, dokümantasyon siteleri ve uzun içerik sayfalarında kullanıcı yönlendirme açısından oldukça etkilidir.
Kritik Kavram: start ve endTrack-piece'in en önemli iki pseudo-class'ı:
- :start Kaydırmanın başlangıç yönündeki parça. Dikeyde thumb'un üstü, yatayda solu.
- :end Kaydırmanın bitiş yönündeki parça. Dikeyde thumb'un altı, yatayda sağı.
Bu yapı, thumb'u merkez alarak iki yönlü bir durum ayrımı yapmanızı sağlar.
Yani track artık tek renkli bir alan değil, geçmiş ve gelecek olarak ikiye ayrılmış olur.
Uyarı: Tarayıcı Tutarsızlıkları:start ve :end pseudo-class'ları tüm WebKit tarayıcılarda tutarlı çalışmaz.
Bu nedenle bu özellik, kritik UI bileşenleri için değil, daha çok görsel zenginleştirme amacıyla kullanılmalıdır.
- İyi Destek: Chrome 90+, Edge 90+, Safari 14+
- Kısıtlı Destek: Eski Chrome/Edge sürümleri
- Hiç Destek Yok: Firefox (her zaman)
Bu yüzden production ortamında mutlaka fallback düşünülmelidir.
Performans NotuTrack-piece stilleri, thumb hareket ettikçe sürekli yeniden hesaplanır ve yeniden çizilir.
Bu da scrollbar'ı aslında küçük bir animasyon sistemi haline getirir.
- Kullanın: Basit renkler ve lineer gradientler
- Kaçının: Karmaşık pattern'ler, yüksek çözünürlüklü resimler, blur efektleri
Ağır stiller, özellikle düşük performanslı cihazlarda scroll akıcılığını bozabilir.
Best Practice: Sadece gerçekten ihtiyaç duyduğunuz durumlarda kullanın. Çoğu UI için standart track yeterlidir.
::-webkit-scrollbar-track-piece, scrollbar'ı sadece bir kontrol değil, bilgi veren bir görsel katmanadönüştürmek isteyenler için güçlü ama dikkatli kullanılması gereken bir araçtır.
|
Durum
|
CSS Hedefleme
|
Görsel Etki
|
|---|---|---|
|
Sayfa Başında
|
:start { background: green; }
:end { background: gray; }
|
Thumb en üstte.
|
|
Sayfa Ortasında
|
:start { background: green; }
:end { background: orange; }
|
Thumb ortada.
|
|
Sayfa Sonunda
|
:start { background: green; }
:end { background: transparent; }
|
Thumb en altta.
|
|
Kombinasyon
|
Tam Seçici
|
Hedeflenen Alan
|
|---|---|---|
|
Temel Parça
|
::-webkit-scrollbar-track-piece
|
Thumb dışındaki TÜM track parçaları
|
|
Yön + Parça
|
:vertical::-webkit-scrollbar-track-piece:start
|
Sadece dikey scrollbar'ın thumb'ın üstündeki parçası |
|
Çift Yön Parçası
|
:horizontal::-webkit-scrollbar-track-piece:end
|
Sadece yatay scrollbar'ın thumb'ın sağındaki parçası |
|
No Button Durumu
|
:no-button::-webkit-scrollbar-track-piece
|
Butonların olmadığı durumdaki track
parçaları |
|
Uygulama
|
:start Stili
|
:end Stili
|
|---|---|---|
|
Video Oynatıcı
(timeline)
|
background: #3b82f6;
|
background: #94a3b8;
|
|
Form Wizard
(adım göstergesi)
|
background: linear-gradient(...);
|
background: #e2e8f0;
|
|
Müzik Çalar
(playlist)
|
background: #ef4444;
|
background: #f3f4f6;
|
<!DOCTYPE html>
<html lang="tr">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>::-webkit-scrollbar - Scrollbar Özelleştirme Demosu</title>
<link rel="stylesheet" href="style.css?v=1.0.150">
</head>
<body>
<div class="container">
<h1>🎨 <code>::-webkit-scrollbar</code> Demo</h1>
<div class="scroll-demo">
<div class="horizontal-content">
<!-- BİLGİ KUTUSU - Scrollbar Anatomisi -->
<div class="info-box">
<strong>📐 Scrollbar Anatomisi</strong><br>
Bu sayfada aşağıdaki tüm pseudo-elementler özelleştirilmiştir:
<div class="anatomy">
<span class="anatomy-item">::-webkit-scrollbar</span>
<span class="anatomy-item">::-webkit-scrollbar-track</span>
<span class="anatomy-item">::-webkit-scrollbar-thumb</span>
<span class="anatomy-item">::-webkit-scrollbar-button</span>
<span class="anatomy-item">::-webkit-scrollbar-corner</span>
<span class="anatomy-item">::-webkit-scrollbar-track-piece:start</span>
<span class="anatomy-item">::-webkit-scrollbar-track-piece:end</span>
</div>
</div>
<!-- KART 1 -->
<div class="card">
<h3>🎯 <code>::-webkit-scrollbar-track-piece</code></h3>
<p><span class="badge badge-green">İlerleme Göstergesi</span> <span class="badge">:start /
:end</span></p>
<p>Scrollbar'da thumb'un <strong>üstündeki alan yeşil</strong>,
<strong>altındaki alan gri</strong> olarak renklendirilmiştir.
</p>
<p>⬇️ <strong>Aşağı kaydırdıkça</strong> yeşil alan büyür, gri alan küçülür!</p>
</div>
<!-- KART 2 -->
<div class="card">
<h3>🖱️ <code>::-webkit-scrollbar-thumb</code></h3>
<p><span class="badge">Gradient Renk</span> <span class="badge">Hover + Scale</span> <span
class="badge">min-height:40px</span></p>
<p>Tutamaç mor-mavi gradient renge sahiptir. Üzerine gelince büyür
(<code>transform: scale()</code>),
tıklayınca koyulaşır. <strong>min-height:40px</strong> ile her zaman tutulabilir boyuttadır.</p>
</div>
<!-- KART 3 -->
<div class="card">
<h3>🔘 <code>::-webkit-scrollbar-button</code> & <code>::-webkit-scrollbar-corner</code></h3>
<p><span class="badge">:decrement</span> <span class="badge">:increment</span> <span
class="badge">SVG Icons</span></p>
<p>Scrollbar yapısnın uçlarına SVG ok ikonları eklenmiştir. Ayrıca yatay + dikey scrollbar aynı anda aktif
olduğunda
sağ-alt köşede <strong>gradient renkli corner</strong> görünecektir.</p>
</div>
<!-- KART 4 -->
<div class="card">
<h3>♿ Erişilebilirlik Notu</h3>
<p><span class="badge">min-height:40px</span> <span class="badge">Hover Feedback</span> <span
class="badge">Active State</span></p>
<p>Thumb minimum 40px yükseklikte tutulmuştur (WCAG önerisi). Hover ve aktif durumlarda görsel geri
bildirim
sağlanmıştır.</p>
</div>
<h3>📊 Yatay Scrollbar Örneği (Geniş Tablo)</h3>
<table>
<thead>
<tr>
<th>ID</th>
<th>Kullanıcı Adı</th>
<th>E-posta</th>
<th>Şehir</th>
<th>Ülke</th>
<th>Kayıt Tarihi</th>
<th>Son Giriş</th>
<th>Durum</th>
</tr>
</thead>
<tbody>
<tr><td>1</td><td>ahmet_yilmaz</td><td>ahmet@example.com</td><td>İstanbul</td><td>Türkiye</td><td>2024-01-15</td><td>2024-03-20</td><td>Aktif</td></tr>
<tr><td>2</td><td>ayse_demir</td><td>ayse@example.com</td><td>Ankara</td><td>Türkiye</td><td>2024-01-20</td><td>2024-03-19</td><td>Aktif</td></tr>
<tr><td>3</td><td>mehmet_kaya</td><td>mehmet@example.com</td><td>İzmir</td><td>Türkiye</td><td>2024-02-01</td><td>2024-03-18</td><td>Pasif</td></tr>
</tbody>
</table>
<div class="card">
<h3>⚠️ Önemli Uyarılar</h3>
<ul>
<li><strong>Standart Değildir:</strong> <code>::-webkit-scrollbar</code> W3C standardı değildir.</li>
<li><strong>Firefox'ta Çalışmaz</strong></li>
<li><strong>Mobil Uyarısı</strong></li>
</ul>
</div>
</div>
</div>
<div style="padding:16px; text-align:center;">
⚡ <strong>::-webkit-scrollbar</strong> Demo
</div>
</div>
</body>
</html>
/* ============================================ */
/* 1. SCROLLBAR'IN ANA KONTEYNERİ (Görünürlük için zorunlu) */
/* ============================================ */
::-webkit-scrollbar {
width: 14px;
/* Dikey scrollbar kalınlığı */
height: 14px;
/* Yatay scrollbar kalınlığı */
background: #f1f5f9;
/* Fallback renk */
}
/* ============================================ */
/* 2. TRACK (RAY) - Pasif arka plan */
/* ============================================ */
::-webkit-scrollbar-track {
background: linear-gradient(145deg, #e2e8f0 0%, #cbd5e1 100%);
border-radius: 20px;
margin: 4px 0;
/* Dikeyde üst/alt boşluk */
box-shadow: inset 0 2px 5px rgba(0, 0, 0, 0.1);
}
/* Yatay track için özel margin */
::-webkit-scrollbar-track:horizontal {
margin: 0 4px;
/* Yatayda sol/sağ boşluk */
}
/* ============================================ */
/* 3. THUMB (TUTAMAÇ) - Hareketli kontrol */
/* ============================================ */
::-webkit-scrollbar-thumb {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
border-radius: 20px;
border: 3px solid transparent;
background-clip: padding-box;
/* İnce görünüm */
min-height: 40px;
/* Minimum boyut - ERİŞİLEBİLİRLİK */
min-width: 40px;
}
/* Hover efekti - Kullanıcıya "beni tutabilirsin" mesajı */
::-webkit-scrollbar-thumb:hover {
background: linear-gradient(135deg, #5a67d8 0%, #6b46a0 100%);
transform: scale(1.02);
}
/* Aktif (sürükleme) durumu */
::-webkit-scrollbar-thumb:active {
background: linear-gradient(135deg, #4c51bf 0%, #553c9a 100%);
cursor: grabbing;
}
/* ============================================ */
/* 4. BUTTONS (OKLAR) - Navigasyon butonları */
/* ============================================ */
::-webkit-scrollbar-button {
background: #94a3b8;
border-radius: 12px;
width: 14px;
height: 14px;
background-size: 8px 8px;
background-repeat: no-repeat;
background-position: center;
}
/* Dikey - Yukarı Ok (decrement) */
::-webkit-scrollbar-button:vertical:decrement {
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='white' viewBox='0 0 24 24'%3E%3Cpath d='M12 8l-6 6 1.41 1.41L12 10.83l4.59 4.58L18 14z'/%3E%3C/svg%3E");
margin-bottom: 4px;
}
/* Dikey - Aşağı Ok (increment) */
::-webkit-scrollbar-button:vertical:increment {
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='white' viewBox='0 0 24 24'%3E%3Cpath d='M12 16l-6-6 1.41-1.41L12 13.17l4.59-4.58L18 10z'/%3E%3C/svg%3E");
margin-top: 4px;
}
/* Yatay - Sol Ok (decrement) */
::-webkit-scrollbar-button:horizontal:decrement {
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='white' viewBox='0 0 24 24'%3E%3Cpath d='M16 18l-6-6 6-6-1.41-1.41L7.17 12l7.42 7.41z'/%3E%3C/svg%3E");
margin-right: 4px;
}
/* Yatay - Sağ Ok (increment) */
::-webkit-scrollbar-button:horizontal:increment {
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='white' viewBox='0 0 24 24'%3E%3Cpath d='M8 18l6-6-6-6 1.41-1.41 7.42 7.41-7.42 7.41z'/%3E%3C/svg%3E");
margin-left: 4px;
}
/* Buton hover durumu */
::-webkit-scrollbar-button:hover {
background-color: #64748b;
transform: scale(1.05);
}
/* ============================================ */
/* 5. CORNER (KÖŞE) - Çift scrollbar'da kesişim */
/* ============================================ */
::-webkit-scrollbar-corner {
background: linear-gradient(135deg, #667eea20, #764ba220);
border-radius: 4px;
}
/* ============================================ */
/* 6. TRACK-PIECE (YOL PARÇALARI) - İlerleme göstergesi */
/* ============================================ */
/* Thumb'un ÜSTÜNDEKİ parça (başlangıç yönü) - OKUNAN kısım */
::-webkit-scrollbar-track-piece:start {
background: linear-gradient(145deg, #22c55e, #16a34a);
border-radius: 20px 20px 4px 4px;
}
/* Thumb'un ALTINDAKİ parça (bitiş yönü) - KALAN kısım */
::-webkit-scrollbar-track-piece:end {
background: linear-gradient(145deg, #cbd5e1, #94a3b8);
border-radius: 4px 4px 20px 20px;
}
/* Yatay scrollbar için track-piece özelleştirmesi */
::-webkit-scrollbar-track-piece:horizontal:start {
border-radius: 20px 4px 4px 20px;
}
::-webkit-scrollbar-track-piece:horizontal:end {
border-radius: 4px 20px 20px 4px;
}
/* ============================================ */
/* SAYFA İÇERİĞİ STİLLERİ (Sadece demo amaçlı) */
/* ============================================ */
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: system-ui, -apple-system, 'Segoe UI', sans-serif;
background: linear-gradient(135deg, #0f172a 0%, #1e293b 100%);
min-height: 100vh;
padding: 40px 20px;
}
.container {
max-width: 800px;
margin: 0 auto;
background: white;
border-radius: 24px;
box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.25);
overflow: hidden;
}
/* Scrollbar'ın görünmesi için içerik alanı */
.scroll-demo {
height: 500px;
overflow-y: scroll;
overflow-x: auto;
padding: 24px;
background: #f8fafc;
}
/* Yatay scrollbar'ı tetiklemek için geniş içerik */
.horizontal-content {
width: 1200px;
}
.card {
background: white;
border-radius: 16px;
padding: 20px;
margin-bottom: 20px;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
border-left: 4px solid #667eea;
}
h1 {
background: linear-gradient(135deg, #667eea, #764ba2);
-webkit-background-clip: text;
background-clip: text;
color: transparent;
padding: 24px 24px 0 24px;
font-size: 1.8rem;
}
.badge {
display: inline-block;
background: #e2e8f0;
padding: 4px 12px;
border-radius: 20px;
font-size: 0.75rem;
font-weight: 600;
margin-right: 8px;
}
.badge-green {
background: #22c55e20;
color: #16a34a;
}
table {
width: 100%;
border-collapse: collapse;
margin: 20px 0;
}
th,
td {
padding: 12px;
text-align: left;
border-bottom: 1px solid #e2e8f0;
}
th {
background: #f1f5f9;
font-weight: 600;
}
.info-box {
background: #fef3c7;
border-left: 4px solid #f59e0b;
padding: 16px;
border-radius: 12px;
margin: 20px 0;
font-size: 0.9rem;
}
.anatomy {
display: flex;
flex-wrap: wrap;
gap: 10px;
margin: 20px 0;
padding: 16px;
background: #1e293b;
border-radius: 16px;
color: white;
}
.anatomy-item {
background: #334155;
padding: 6px 12px;
border-radius: 20px;
font-family: monospace;
font-size: 0.75rem;
}
hr {
margin: 24px 0;
border: none;
border-top: 2px solid #e2e8f0;
}