Yatay taşmayı arayan herkesin bildiği his: metin sağdan kesiliyor ve hangi öğenin yaptığı belli değil. Üçünü de ölçerek buldum, ikisi beklediğim yerde değildi.
Bu sitenin ana sayfası bir tasarım aracı çıktısından dönüştürülmüştü ve hiç medya sorgusu içermiyordu. Telefonda açıldığında sayfa yatay kayıyor, metin sağdan kesiliyordu.
İlk iş ölçmekti. 375 px genişlikte:
documentElement.clientWidth → 375
documentElement.scrollWidth → 738
Belge, görünen alanın iki katı. Yani tek bir öğe her şeyi genişletiyor ve sayfanın tamamı 738 px’lik bir düzende diziliyor.
Sağa taşan her öğeyi listeleyen küçük bir betik yeterli oldu:
const vw = document.documentElement.clientWidth;
[...document.querySelectorAll('body *')]
.map((el) => ({ el, r: el.getBoundingClientRect() }))
.filter(({ r }) => r.width > 0 && r.right > vw + 1)
.sort((a, b) => b.r.right - a.r.right);
Listenin başındaki öğe şuydu:
position: absolute;
top: -320px;
left: 50%;
transform: translateX(-50%);
width: 1100px;
height: 760px;
background: radial-gradient(...);
pointer-events: none;
Başlığın arkasındaki dekoratif yeşil parıltı. Görünmüyor bile — pointer-events: none, kenarları tamamen şeffaf.
Yaygın varsayım şu: mutlak konumlu bir öğe akıştan çıktığı için düzeni etkilemez. Kaydırma alanı için bu doğru değil. Öğe sağa taşarsa kaydırılabilir alanı büyütür ve belge genişler.
Burada 1100 px genişliğindeki kutu left: 50% ile 187 px’e konuyor, translateX(-50%) ile 550 px sola çekiliyor: sol kenar −362, sağ kenar 738. Sol taraftaki taşma kaydırma alanını büyütmüyor (ters yön), sağdaki büyütüyor. Belge genişliği tam olarak oradan geliyordu.
overflow koymamakİlk akla gelen çözüm body { overflow-x: hidden }. Kullanmadım: gövdeyi kaydırma kabına çevirmek üstteki position: sticky başlığı bozma riski taşıyor.
Bunun yerine parıltının kendisi kısıtlandı — küçük ekranda width: 100%. Sorunu kaynağında çözmek, semptomu kırpmaktan daha ucuz.
Düzenin tamamı satır içi style özniteliğindeydi, öğelerin sınıfı yoktu. Satır içi stil, stil sayfasındaki kuralı her zaman yendiği için medya sorgusunun !important alması gerekiyordu — o kısım beklenendi. Hedefleme için ise öznitelik seçicisi kullandım:
[style*="grid-template-columns:340px 1fr"] {
grid-template-columns: 1fr !important;
}
Kural hiç uygulanmadı. Hata da vermedi.
Sebep şuydu: sayfadaki “kaydırınca belir” betiği el.style.opacity ve el.style.transform yazıyor. JavaScript bir stil özelliğini yazdığı anda tarayıcı style özniteliğinin tamamını yeniden seriye çeviriyor:
grid-template-columns:340px 1fr ← HTML'de yazdığım
grid-template-columns: 340px 1fr ← JS dokunduktan sonra
İki nokta üst üsteden sonra bir boşluk. Alt dize eşleşmesi bozuluyor, seçici artık hiçbir şeyi seçmiyor ve CSS sessizce hiçbir şey yapmıyor.
[style*="…"] kırılgan bir hedefleme yöntemi ve başarısızlığı görünmez. Düzen öğelerine gerçek sınıf eklemek beş dakika sürdü ve sorunu tamamen ortadan kaldırdı.
Sınıflara geçtikten sonra ekran görüntüsü aldım ve sayfa hâlâ kırık görünüyordu. Kullandığım komut:
chrome --headless=new --window-size=390,2400 --screenshot=out.png ...
Oysa gerçek tarayıcıda ölçtüğümde scrollWidth 375, taşan öğe sayısı 0’dı. İkisi aynı anda doğru olamazdı.
Açıklama: Windows’ta pencerenin bir asgari genişliği var. Headless Chrome istenen 390 px’i pencere boyutu olarak tam veremiyor, içerik daha geniş bir düzende diziliyor ama ekran görüntüsü istenen 390 px’de alınıyor. Sonuç, düzeltilmiş bir sayfanın kırık görünmesi.
Yani doğrulama aracı, düzelttiğim şeyin düzelmediğini söylüyordu. Ölçüyü gerçek tarayıcıda scrollWidth ve getBoundingClientRect() ile aldığımda tablo netleşti.
overflow: hidden çalışır ama position: sticky gibi başka şeyleri sessizce bozar.[style*="…"] ile hedefleme yapma. JavaScript bir stil özelliğine dokunduğu anda öznitelik metni değişiyor ve seçici sessizce ıskalıyor.