Mengapa persentase margin / padding dalam CSS selalu dihitung terhadap lebar?

130

Jika Anda melihat spec model kotak CSS , Anda akan mengamati yang berikut:

Persentase [margin] dihitung sehubungan dengan lebar blok berisi kotak yang dihasilkan. Perhatikan bahwa ini juga berlaku untuk 'margin-top' dan 'margin-bottom'. Jika lebar blok yang mengandung tergantung pada elemen ini, maka tata letak yang dihasilkan tidak terdefinisi dalam CSS 2.1. (penekanan milikku)

Ini memang benar. Tapi mengapa ? Apa yang akan memaksa orang untuk mendesainnya dengan cara ini? Sangat mudah untuk memikirkan skenario di mana Anda inginkan, misalnya hal tertentu untuk selalu turun 25% dari bagian atas halaman, tetapi sulit untuk datang dengan alasan mengapa Anda ingin bantalan vertikal relatif terhadap ukuran horizontal dari orang tua.

Berikut adalah contoh dari fenomena yang saya maksudkan:

<div style="border: 1px solid red; margin: 0; padding: 0; width: 200px; height: 800px;">
  This div is 200x800.
  <div style="border: 1px solid blue; margin: 10% 0 0 10%;">
    This div has top-margin of 10% and left-margin of 10% with respect to its parent.
  </div>
</div>

http://jsfiddle.net/8JDYD/

mqp
sumber
3
Pikiran awal saya adalah bahwa hal itu akan menyebabkan ambiguitas makna margin: 25%sebenarnya. Itu tidak akan menjadi margin yang genap, meskipun kode menunjukkan itu. Saya tidak punya bukti untuk mendukung ini, tetapi tampaknya masuk akal.
Ryan Kinal
4
Aku memikirkan pikiranku . Ketinggiannya jauh lebih berubah dari lebar, sehingga akan membuat margin bergeser dengan cara yang sulit diprediksi kapan pun konten berubah.
RichardTowers
1
@Ryan: Itu benar, itu tidak akan menjadi margin yang genap, tetapi sekali lagi, jika Anda mengatakan height: 10%; width: 10%Anda tidak akan mendapatkan elemen persegi juga.
mqp
4
Menurut dev.w3.org/csswg/css3-box/#the-margin-properties yang dinyatakannya Note that in a horizontal flow, percentages on ‘margin-top’ and ‘margin-bottom’ are relative to the width of the containing block, not the height (and in vertical flow, ‘margin-left’ and ‘margin-right’ are relative to the height, not the width).Jadi berjalan dua arah
Adam Sweeney
1
@Ryan Saya pikir kami punya pemenang. Lihat di sini untuk demo - jsFiddle
RichardTowers

Jawaban:

60

Mentransfer komentar saya ke jawaban, karena itu masuk akal. Namun, harap dicatat bahwa ini adalah dugaan yang tidak berdasar. Alasan sebenarnya mengapa spec ditulis dengan cara ini masih, secara teknis, tidak diketahui.

Tinggi elemen ditentukan oleh tinggi anak-anak. Jika suatu elemen memiliki padding-top: 10% (relatif terhadap tinggi induk), itu akan mempengaruhi ketinggian induk. Karena tinggi anak tergantung pada tinggi induk, dan tinggi induk tergantung pada tinggi anak, kita akan memiliki tinggi yang tidak akurat, atau loop tak terbatas. Tentu, ini hanya memengaruhi kasus di mana offset parent === parent, tetapi tetap saja. Ini kasus aneh yang sulit diselesaikan.

Pembaruan: Kalimat pasangan terakhir mungkin tidak sepenuhnya akurat. Ketinggian elemen daun (anak tanpa anak) memiliki efek pada ketinggian semua elemen di atasnya, jadi ini mempengaruhi banyak situasi yang berbeda.

Ryan Kinal
sumber
1
Perhatikan bahwa ada pengecualian untuk aturan ini - bagian 10.6 dari CSS2.1 mencakup hampir semua contoh penghitungan ketinggian untuk berbagai jenis kotak. Dan memang, kasus-kasus yang melibatkan saling ketergantungan antara orang tua dan anak cenderung menyebabkan perilaku yang tidak jelas.
BoltClock
1
@ sanjaypoyzer Saya kira dalam kasus paling sederhana bahwa browser menghitung lebar blok dari luar di (root ke tips), kemudian mengalir konten ke blok tersebut untuk menentukan ketinggian mereka (tips untuk root).
sam
9
Mengapa W3C terus melakukan ini? Rupanya 'semantik' untuk W3C adalah setara dengan harus melayani orang yang tidak bisa berpikir secara logis, yang tidak masuk akal. Ini seperti mengeluh tentang betapa membingungkan dan bodohnya orang di dunia kemudian menyebarkan lebih banyak kebingungan dan kebodohan. Alasan yang Anda berikan tidak masuk akal: argumen yang sama berlaku untuk lebar, namun itu berfungsi dengan baik. Yang diperlukan hanyalah menetapkan konteks dan arah yang ditentukan ketinggian, kecuali jika tinggi induk ditetapkan dalam piksel atau sesuatu yang tidak dapat diubah, maka tidak ada banyak masalah.
u353
3
Ketergantungan itu adalah formula aljabar yang memiliki solusi dan tidak akan menghasilkan loop tak terbatas kecuali Anda memilih untuk menyelesaikannya dengan cara yang tidak menghargai ini. Katakanlah tinggi orangtua h_p. Bagian atas padding 10% akan membuat anak tinggi h_c = h_ci + 0.1h_p, di mana h_citinggi bagian dalam anak dan tidak tergantung pada tinggi orangtua. Untuk satu anak Anda cukup menemukan tinggi orangtua dari persamaan h_p = h_ci + 0.1h_p=> h_p = h_ci / 0.9. Anda selalu dapat melakukan ini, tidak peduli berapa banyak anak yang Anda miliki, bahkan untuk lapisan yang berbeda. Hanya satu yang tidak diketahui ( h_p) dan satu persamaan.
Juni
2
Saya tidak berpikir perhitungan yang tak terbatas adalah alasannya. Alasan sederhana adalah: menggunakan widthhasil dalam masalah yang sama secara horizontal.
Joy
30

Agar margin "n%" (dan padding) sama dengan margin-atas / margin-kanan / margin-bawah / margin-kiri, keempatnya harus relatif terhadap basis yang sama. Jika atas / bawah menggunakan basis berbeda dari kiri / kanan ', maka margin "n%" (dan bantalan) tidak akan berarti hal yang sama di keempat sisi.

(Perhatikan juga bahwa margin atas / bawah relatif terhadap lebar memungkinkan peretasan CSS aneh yang memungkinkan Anda untuk menentukan kotak dengan rasio aspek yang tidak berubah ... bahkan jika kotak tersebut diperbesar ulang.)

Chuck Kollars
sumber
... jawaban yang sangat sederhana. Meskipun semua dugaan di atas memiliki kelebihan, ini adalah poin yang cukup bagus. Tampaknya mungkin suatu kasus di mana beberapa solusi akan benar sehingga mereka hanya memilih yang paling mungkin digunakan satu .... mungkin?
dudewad
1
Saya kira itu akan menyenangkan untuk memiliki elemen tambahan dalam sintaks sehingga Anda dapat menulis katakan padding: n [type]. Jadi Anda akan memiliki padding: 5% logical(apa yang OP sarankan) sebagai lawan padding: 5% widthdengan parameter kedua default ke "width" untuk kompatibilitas mundur.
Juni
5
"n% margin (dan padding) tidak akan berarti hal yang sama di keempat sisi" - Tapi mengapa itu akan menjadi masalah?
Herbertusz
4

Saya memilih jawaban dari @ChuckKollars setelah bermain dengan ini JSFiddle (di Chrome 46.0.2490.86) dan merujuk ke posting ini (ditulis dalam bahasa Cina).


Alasan utama menentang dugaan perhitungan tak terbatas adalah bahwa: menggunakan widthmenghadapi masalah perhitungan tak terbatas yang sama .

Lihat JSFiddle ini , parentlayarnya inline-block, yang memenuhi syarat untuk menentukan margin / padding di atasnya. The childmemiliki nilai marjin 20%. Jika kita mengikuti dugaan perhitungan tak terbatas :

  1. Lebar childtergantung padaparent
  2. Lebar parenttergantung padachild

Tetapi sebagai hasilnya, Chrome menghentikan perhitungan di suatu tempat, menghasilkan:

masukkan deskripsi gambar di sini

Jika Anda mencoba memperluas panel "hasil" secara horizontal di JSFiddle, Anda akan menemukan bahwa lebar mereka tidak akan berubah. Harap perhatikan bahwa konten dalam childterbungkus menjadi dua baris (bukan, katakanlah, satu baris), mengapa? Saya kira Chrome hanya menuliskannya di suatu tempat. Jika Anda mengeditchild konten untuk membuatnya lebih ( JSFiddle ), Anda akan menemukan bahwa selama ada ruang tambahan secara horizontal, Chrome menyimpan konten dua baris.

Jadi kita bisa melihat: ada beberapa cara untuk mencegah perhitungan yang tak terbatas .


Saya setuju dengan dugaan bahwa: desain ini hanya untuk menjaga empat nilai margin / padding berdasarkan ukuran yang sama.

posting ini (ditulis dalam bahasa Cina) juga mengusulkan alasan lain adalah bahwa: itu karena orientasi membaca / mengeset. Kita membaca dari atas ke bawah, dengan lebar tetap dan tinggi tak terbatas (sebenarnya).

Kegembiraan
sumber
Ini karena halaman web gulir secara vertikal ke arah yang umumnya tidak terbatas; jadi lebarnya bisa dihitung dari lebar jendela browser. Satu-satunya cara elemen lebih lebar dari layar adalah jika Anda menentukan lebarnya menjadi lebih besar. Elemen blok yang umum adalah lebar 100% dan berkembang secara otomatis ke arah vertikal (tidak diketahui). Itu sebabnya lebar tidak memiliki masalah yang sama.
Lucent Fox
3

Saya menyadari OP bertanya mengapa spesifikasi CSS mendefinisikan persentase margin atas / bawah sebagai% dari lebar (dan tidak, seperti yang akan diasumsikan, tinggi), tapi saya pikir itu mungkin juga berguna untuk memposting solusi potensial.

Sebagian besar browser modern mendukung vw dan vh sekarang yang memungkinkan Anda menentukan angka margin terhadap lebar viewport dan tinggi viewport.

100vw / 100vh sama dengan 100% lebar / tinggi 100% (masing-masing) jika tidak ada scrollbar; jika ada bilah gulir, nomor viewport tidak menjelaskan hal ini (sementara% angka melakukannya). Untungnya, hampir semua browser menggunakan ukuran scrollbar 17px ( lihat di sini ), sehingga Anda dapat menggunakan fungsi css calc untuk menjelaskan hal ini. Jika Anda tidak tahu apakah bilah gulir akan muncul atau tidak, maka solusi ini tidak akan berfungsi.

Sebagai contoh: Dengan asumsi tidak ada scrollbar horizontal, margin atas 50% tinggi, dapat didefinisikan sebagai "margin-top: 50vh;". Dengan scrollbar horizontal, ini dapat didefinisikan sebagai "margin-top: calc (0,5 * (100vh - 17px));" (ingat bahwa operator minus dan plus di calc membutuhkan ruang di kedua sisi!).

VKK
sumber
1
Ini adalah solusi yang berguna dalam banyak kasus, tetapi ada banyak contoh di mana itu tidak bekerja (misalnya jika Anda mencoba untuk membuat konten sesuai dengan ukuran wadah flexbox yang tumbuh untuk mengisi ruang yang tersedia sementara ada kotak lain dengan konten variabel).
Jules