เหตุใดเปอร์เซ็นต์ระยะขอบ / ช่องว่างใน CSS จึงคำนวณเทียบกับความกว้างเสมอ


130

หากคุณดูข้อมูลจำเพาะโมเดลกล่อง CSSคุณจะสังเกตสิ่งต่อไปนี้:

เปอร์เซ็นต์ [ระยะขอบ] คำนวณตามความกว้างของบล็อกที่มีกล่องที่สร้างขึ้น โปรดทราบว่านี่เป็นจริงสำหรับ "margin-top" และ "margin-bottom" เช่นกัน หากความกว้างของบล็อกที่มีขึ้นอยู่กับองค์ประกอบนี้เค้าโครงผลลัพธ์จะไม่ได้กำหนดไว้ใน CSS 2.1 (เน้นเหมือง)

นี่เป็นความจริงแน่นอน แต่ทำไม ? มีอะไรในโลกที่บังคับให้ทุกคนออกแบบด้วยวิธีนี้? เป็นเรื่องง่ายที่จะนึกถึงสถานการณ์ที่คุณต้องการเช่นบางสิ่งบางอย่างจะต้องลดลง 25% จากด้านบนของหน้าเสมอ แต่ก็ยากที่จะหาเหตุผลว่าทำไมคุณถึงต้องการให้ช่องว่างในแนวตั้งเทียบกับขนาดแนวนอนของ ผู้ปกครอง

นี่คือตัวอย่างของปรากฏการณ์ที่ฉันอ้างถึง:

<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/


3
ความคิดแรกของฉันคือมันจะทำให้เกิดความคลุมเครือว่าmargin: 25%แท้จริงแล้วหมายถึงอะไร มันจะไม่เป็นระยะขอบแม้ว่ารหัสจะบอกว่าเป็น ฉันไม่มีหลักฐานที่จะสำรองข้อมูลนี้ แต่ดูเหมือนว่าสมเหตุสมผล
Ryan Kinal

4
jsFiddle ของความคิดของฉัน ความสูงสามารถเปลี่ยนแปลงได้มากกว่าความกว้างมากดังนั้นจึงทำให้ระยะขอบเปลี่ยนไปรอบ ๆ ในรูปแบบที่ยากต่อการคาดเดาเมื่อใดก็ตามที่เนื้อหาเปลี่ยนไป
RichardTowers

1
@Ryan: นั่นเป็นเรื่องจริงมันจะไม่เป็นส่วนต่าง แต่ถ้าคุณบอกว่าheight: 10%; width: 10%คุณจะไม่ได้รับองค์ประกอบสี่เหลี่ยมจัตุรัสอีกด้วย
mqp

4
อ้างอิงจากdev.w3.org/csswg/css3-box/#the-margin-properties มัน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).จึงเป็นไปทั้งสองทาง
Adam Sweeney

1
@Ryan ฉันคิดว่าเรามีผู้ชนะ ดูการสาธิตที่นี่ - jsFiddle
RichardTowers

คำตอบ:


60

การถ่ายโอนความคิดเห็นของฉันไปเป็นคำตอบเพราะมันสมเหตุสมผล อย่างไรก็ตามโปรดทราบว่านี่เป็นการคาดเดาที่ไม่มีมูล เหตุผลที่แท้จริงว่าทำไมจึงเขียนข้อมูลจำเพาะในลักษณะนี้ในทางเทคนิคไม่ทราบ

ความสูงขององค์ประกอบกำหนดโดยความสูงของเด็ก หากองค์ประกอบมี padding-top: 10% (เทียบกับความสูงระดับบนสุด) นั่นจะส่งผลต่อความสูงของพาเรนต์ เนื่องจากความสูงของเด็กขึ้นอยู่กับความสูงของพ่อแม่และความสูงของพ่อแม่นั้นขึ้นอยู่กับความสูงของเด็กเราจึงมีความสูงที่ไม่ถูกต้องหรือเป็นวงที่ไม่มีที่สิ้นสุด แน่นอนว่าสิ่งนี้มีผลเฉพาะกรณีที่ offset parent === parent เท่านั้น แต่ยังคงอยู่ เป็นกรณีแปลก ๆ ที่แก้ไขได้ยาก

อัปเดต: ประโยคคู่สุดท้ายอาจไม่ถูกต้องทั้งหมด ความสูงขององค์ประกอบใบไม้ (เด็กที่ไม่มีลูก) มีผลต่อความสูงขององค์ประกอบทั้งหมดด้านบนดังนั้นสิ่งนี้จึงส่งผลต่อสถานการณ์ต่างๆมากมาย


1
โปรดทราบว่ามีข้อยกเว้นสำหรับกฎนี้ - ส่วนที่ 10.6 ของ CSS2.1 ครอบคลุมเกือบทุกกรณีของการคำนวณความสูงสำหรับกล่องประเภทต่างๆ และแน่นอนกรณีที่เกี่ยวข้องกับการพึ่งพาอาศัยกันระหว่างผู้ปกครองและเด็กที่มีส่วนสูงมักจะนำไปสู่พฤติกรรมที่ไม่ได้กำหนด
BoltClock

1
@sanjaypoyzer ฉันเดาในกรณีที่ง่ายที่สุดที่เบราว์เซอร์คำนวณความกว้างของบล็อกจากด้านนอกใน (รูทไปยังเคล็ดลับ) จากนั้นจึงไหลเนื้อหาไปยังบล็อกเหล่านั้นเพื่อกำหนดความสูง (เคล็ดลับในการรูท)
sam

9
ทำไม W3C ถึงทำเช่นนี้อย่างต่อเนื่อง? เห็นได้ชัดว่า 'ความหมาย' สำหรับ W3C นั้นเทียบเท่ากับการต้องรองรับคนที่ไม่สามารถคิดอย่างมีเหตุผลซึ่งไม่สมเหตุสมผล มันเหมือนกับการบ่นเกี่ยวกับความสับสนและความโง่เขลาในโลกจากนั้นทำให้ความสับสนและความโง่เขลามากขึ้น เหตุผลที่คุณระบุไม่สมเหตุสมผล: อาร์กิวเมนต์เดียวกันนี้ใช้กับความกว้าง แต่ก็ใช้ได้ดี สิ่งที่จำเป็นคือกำหนดบริบทและทิศทางที่กำหนดความสูงเว้นแต่จะกำหนดความสูงของพาเรนต์เป็นพิกเซลหรือสิ่งที่ไม่เปลี่ยนรูปก็ไม่มีปัญหามากนัก
u353

3
การพึ่งพานั้นเป็นสูตรทางพีชคณิตซึ่งมีวิธีแก้ปัญหาและจะไม่ส่งผลให้เกิดการวนซ้ำที่ไม่มีที่สิ้นสุดเว้นแต่คุณจะเลือกแก้ปัญหาด้วยวิธีที่ไม่เคารพสิ่งนี้ h_pพูดความสูงผู้ปกครอง ด้านบน padding 10% จะทำให้ความสูงของเด็กh_c = h_ci + 0.1h_pซึ่งh_ciเป็นความสูงภายในของเด็กและไม่ได้ขึ้นอยู่กับความสูงของพ่อแม่ สำหรับเด็กคนหนึ่งคุณก็พบความสูงผู้ปกครองจากสมการ=>h_p = h_ci + 0.1h_p h_p = h_ci / 0.9คุณสามารถทำได้เสมอไม่ว่าคุณจะมีลูกกี่คนแม้จะมีช่องว่างภายในที่ต่างกันก็ตาม มันเป็นเพียงh_pสมการที่ไม่รู้จัก ( ) และสมการเดียว
jeteon

2
ฉันไม่คิดว่าการคำนวณที่ไม่มีที่สิ้นสุดเป็นเหตุผล เหตุผลง่ายๆก็คือการใช้widthผลลัพธ์ในปัญหาเดียวกันในแนวนอน
Joy

30

สำหรับระยะขอบ "n%" (และช่องว่างภายใน) จะเหมือนกันสำหรับระยะขอบบน / ขอบขวา / ระยะขอบล่าง / ระยะขอบซ้ายทั้งสี่จะต้องสัมพันธ์กับฐานเดียวกัน หากบน / ล่างใช้ฐานที่แตกต่างจากซ้าย / ขวา "ระยะขอบ" n% "(และช่องว่างภายใน) จะไม่ได้หมายความว่าเหมือนกันทั้งสี่ด้าน

(นอกจากนี้โปรดทราบว่าการมีขอบบน / ล่างที่สัมพันธ์กับความกว้างจะช่วยให้แฮ็ค CSS แปลก ๆ ที่ให้คุณระบุช่องที่มีอัตราส่วนกว้างยาวไม่เปลี่ยนแปลง ... แม้ว่ากล่องจะถูกปรับขนาดใหม่ก็ตาม)


... คำตอบง่ายๆที่น่าประหลาดใจ แม้ว่าการคาดเดาทั้งหมดข้างต้นจะมีข้อดี แต่นี่ก็เป็นจุดที่ดีทีเดียว ดูเหมือนว่าอาจจะเป็นกรณีที่วิธีแก้ปัญหาหลาย ๆ วิธีจะถูกต้องดังนั้นพวกเขาจึงเลือกวิธีที่น่าจะใช้มากที่สุด ....
dudewad

1
ฉันคิดว่าคงจะดีถ้ามีองค์ประกอบพิเศษในไวยากรณ์เพื่อให้คุณสามารถเขียนพูดpadding: n [type]ได้ ดังนั้นคุณจะมีpadding: 5% logical(สิ่งที่ OP แนะนำ) ตรงข้ามpadding: 5% widthกับพารามิเตอร์ที่สองที่มีค่าเริ่มต้นเป็น "width" สำหรับความเข้ากันได้แบบย้อนกลับ
jeteon

5
"n% margin (และ padding) ไม่ได้หมายถึงสิ่งเดียวกันทั้งสี่ด้าน" - แต่ทำไมถึงเป็นปัญหา
Herbertusz

4

ฉันโหวตคำตอบจาก @ChuckKollars หลังจากเล่นกับJSFiddleนี้(บน Chrome 46.0.2490.86) และอ้างถึงโพสต์นี้ (เขียนเป็นภาษาจีน)


เหตุผลหลักในการคาดเดาการคำนวณที่ไม่มีที่สิ้นสุดคือการใช้widthเผชิญกับปัญหาการคำนวณที่ไม่สิ้นสุดเหมือนกัน

ดูJSFiddleนี้ซึ่งparentจอแสดงผลinline-blockมีสิทธิ์กำหนดระยะขอบ / ช่องว่างภายใน มีค่าอัตรากำไรขั้นต้นchild 20%หากเราทำตามการคาดเดาการคำนวณที่ไม่มีที่สิ้นสุด :

  1. ความกว้างของchildขึ้นอยู่กับparent
  2. ความกว้างของparentขึ้นอยู่กับchild

แต่ด้วยเหตุนี้ Chrome จึงหยุดการคำนวณที่ใดที่หนึ่งผลลัพธ์:

ป้อนคำอธิบายภาพที่นี่

หากคุณพยายามขยายแผง "ผลลัพธ์" ในแนวนอนบน JSFiddle คุณจะพบว่าความกว้างของมันจะไม่เปลี่ยนแปลง โปรดทราบว่าเนื้อหาในchildนั้นถูกรวมเป็นสองบรรทัด (ไม่ใช่พูดบรรทัดเดียว) ทำไม? ฉันเดาว่า Chrome แค่ฮาร์ดโค้ดไว้ที่ไหนสักแห่ง หากคุณแก้ไขchildเนื้อหาเพื่อให้มากขึ้น ( JSFiddle ) คุณจะพบว่าตราบใดที่มีพื้นที่เพิ่มเติมในแนวนอน Chrome จะเก็บเนื้อหาไว้สองบรรทัด

ดังนั้นเราจึงสามารถดู: มีวิธีที่จะป้องกันไม่ให้มีการคำนวณที่ไม่มีขีด จำกัด บางอย่าง


ฉันเห็นด้วยกับการคาดเดาที่ว่า: การออกแบบนี้เป็นเพียงเพื่อให้ค่าขอบ / ช่องว่างทั้งสี่ตามการวัดเดียวกัน

โพสต์นี้ (เขียนเป็นภาษาจีน) ยังเสนอเหตุผลอีกประการหนึ่งคือนั่นเป็นเพราะแนวการอ่าน / เรียงพิมพ์ เราอ่านจากบนลงล่างโดยมีความกว้างคงที่และความสูงไม่สิ้นสุด (แทบ)


เนื่องจากหน้าเว็บเลื่อนในแนวตั้งในทิศทางที่ไม่สิ้นสุดโดยทั่วไป ดังนั้นความกว้างสามารถคำนวณได้จากความกว้างของหน้าต่างเบราว์เซอร์ วิธีเดียวที่องค์ประกอบจะกว้างกว่าหน้าจอคือหากคุณกำหนดความกว้างให้ใหญ่ขึ้น องค์ประกอบบล็อกโดยทั่วไปมีความกว้าง 100% และขยายโดยอัตโนมัติในแนวตั้ง (ไม่ทราบ) นั่นเป็นเหตุผลที่ความกว้างไม่มีปัญหาเดียวกัน
Lucent Fox

3

ฉันตระหนักดีว่า OP กำลังถามว่าทำไมข้อกำหนด CSS จึงกำหนดเปอร์เซ็นต์ระยะขอบบน / ล่างเป็น% ของความกว้าง (และไม่ใช่ตามที่คาดเดาคือความสูง) แต่ฉันคิดว่าการโพสต์วิธีแก้ปัญหาที่เป็นไปได้อาจมีประโยชน์เช่นกัน

เบราว์เซอร์ที่ทันสมัยส่วนใหญ่รองรับ vw และ vh ในขณะนี้ซึ่งช่วยให้คุณระบุหมายเลขระยะขอบเทียบกับความกว้างของวิวพอร์ตและความสูงของวิวพอร์ต

100vw / 100vh เท่ากับความกว้าง 100% / ความสูง 100% (ตามลำดับ) หากไม่มีแถบเลื่อน หากมีแถบเลื่อนหมายเลขวิวพอร์ตจะไม่คำนึงถึงสิ่งนี้ (ในขณะที่ตัวเลข% ทำ) โชคดีที่เบราว์เซอร์เกือบทั้งหมดใช้ขนาดแถบเลื่อน 17px ( ดูที่นี่ ) ดังนั้นคุณจึงสามารถใช้ฟังก์ชัน css calc เพื่ออธิบายสิ่งนี้ได้ หากคุณไม่ทราบว่าจะมีแถบเลื่อนปรากฏขึ้นหรือไม่แสดงว่าวิธีนี้ใช้ไม่ได้

ตัวอย่างเช่นสมมติว่าไม่มีแถบเลื่อนแนวนอนระยะขอบบน 50% ของความสูงสามารถกำหนดเป็น "margin-top: 50vh;" ด้วยแถบเลื่อนแนวนอนสามารถกำหนดเป็น "margin-top: calc (0.5 * (100vh - 17px));" (จำไว้ว่าตัวดำเนินการลบและบวกในการคำนวณต้องการช่องว่างทั้งสองด้าน!)


1
เป็นวิธีแก้ปัญหาที่มีประโยชน์ในหลาย ๆ กรณี แต่มีตัวอย่างมากมายที่ใช้ไม่ได้ (เช่นหากคุณพยายามทำให้เนื้อหาเหมาะสมกับขนาดของคอนเทนเนอร์เฟล็กบ็อกซ์ที่เติบโตขึ้นเพื่อเติมเต็มพื้นที่ว่างในขณะที่มีอีกกล่องหนึ่งที่มี เนื้อหาตัวแปร)
Jules
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.