分享

[译] 一篇全面的CSS布局学习指南 (下)

 jswcy163 2018-07-11

接上篇


6. 显示顺序和文档顺序

在文章的最开始,我建议你以从上到下的阅读顺序来组织你的文档顺序,这样会有助于可读性和CSS的布局方式。从我们关于弹性盒子和CSS网格的简短介绍来看,你可以发现用这些布局方法可能会极大地改变页面展示的元素在文档中的顺序。这可能会导致一个隐含的问题。

在一些非可视化的应用场景中,浏览器会遵循文档源码来进行使用。因此,屏幕阅读器会读取文档的顺序,此外使用键盘tab键来浏览的用户访问文档的顺序是基于源码的顺序,而不是元素展示的顺序。许多屏幕阅读器的用户并非完全失明,他们可能在使用屏幕阅读器的同时也能够看到这些元素在文档的哪个部分。在这些情况下,当与源码进行对比时,这种混乱的页面展现可能会令人充满迷惑。

当你改变了元素在文档中原来的顺序时,一定确保知道自己在做什么。如果你发现你自己正在CSS中重新排序你的元素,你应该去回头看看是否要重新组织你的页面元素。你可以通过使用tab访问来测试一下你的页面。

6.1. 关于显示顺序和文档顺序的其他阅读资料

  • “CSS Grid Layout and Accessibility,” Web technology for developers, MDN web docs, Mozilla

  • “HTML Source Order vs CSS Display Order,” Adrian Roselli

  • “Flexbox And The Keyboard Navigation Disconnect,” Code Things, Tink

  • “The Responsive Order Conflict For Keyboard Focus,” Alastair Campbell

7. 盒模型的生成(box generation)

你写在网页里的任何东西都会生成一个盒子(box),这篇文章讨论的所有东西其实都是如何能够使用CSS来按照你的设计布局这些盒子。然而,在某些情况下,你可能根本不想创建一个盒子。有两个display的属性值会帮你处理这种情况。

7.1 不生成盒子或内容(display: none

如果你希望元素以及它所有的内容(包括所有子元素)都不会生成,你可以使用display: none。这样元素就不会被展示,并且不会保留其本该占有的空间。

.item {

     display: none;

}

7.2 不生成该元素,但是生成其所有子元素(display: contents

display: contentdisplay的一个新的属性值。为一个元素应用display: content属性会导致其自身的盒子不生成但所有的子元素都会照常生成。这有什么用呢?试想一下,如果你希望一个弹性布局或网格布局中的非直接子元素能应用这些布局,这就会非常有用。

在下面这个例子里,第一个弹性项包含了两个子元素,由于它被设为display: contents,它的盒子不会生成并且它的两个子元素会成为弹性项,并被当作弹性盒子容器的直接子元素来布局。

div class='container'>

    div class='item'>

        div class='subitem'>Adiv>

        div class='subitem'>Bdiv>

    div>

    div class='item'>2div>

    div class='item'>3div>

div>

body {

     padding: 20px;

     font: 1em Helvetica Neue, Helvetica, Arial, sans-serif;

}

 {

    box-sizing: border-box;

}

 {

     margin: 0 0 1em 0;

}

 .container {

     width: 500px;

     border: 5px solid rgb(111,41,97);

     border-radius: .5em;

     padding: 10px;

     display: flex;

}

 .item {

     flex: 1 1 200px;

     padding: 10px;

     background-color: rgba(111,41,97,.3);

     border: 2px solid rgba(111,41,97,.5);

}

 .subitem {

     padding: 10px;

     background-color: rgba(193,225,237,.3);

     border: 2px solid rgba(193,225,237,.5);

}

 .container .item:first-child {

     display: contents;

}

example: Smashing Guide to Layout: display: contents on Codepen

https:///rachelandrew/pen/GdLBRR

8. 对齐

在以前,要实现对齐往往会用到一些很'tricky'的方式,并且能够使用的方法也非常有限。随着CSS盒模型对齐(box alignment module)的出现,这一切都发生了变化。你将会使用它来控制网格容器与弹性盒子容器中的对齐。未来其他的各种布局方法都会应用这些对齐属性。盒模型对齐(box alignment specification)规范中的一系列详细属性如下:

  • justify-content

  • align-content

  • place-content

  • justify-items

  • align-items

  • place-items

  • justify-self

  • align-self

  • place-self

  • row-gap

  • column-gap

  • gap

由于不同的布局模型有不同的特性,因此用于不同布局模型的对齐属性会有一些表现上的差异。让我们来看看在一些简单的网格与弹性布局中对齐是如何工作的。

align-itemsjustify-items属性相对是align-selfjustify-self属性的一种批量形式。这些属性会控制与元素在其网格区域(grid area)中的对齐情况。

div class='container'>

    div>1div>

    div>2div>

    div>3div>

    div>4div>

    div class='special'>5div>

div>

body {

     padding: 20px;

     font: 1em Helvetica Neue, Helvetica, Arial, sans-serif;

}

 {

    box-sizing: border-box;

}

 {

     margin: 0 0 1em 0;

}

 .container {

     width: 500px;

     border: 5px solid rgb(111,41,97);

     border-radius: .5em;

     padding: 10px;

     display: grid;

     grid-template-columns: 1fr 1fr 1fr;

     grid-auto-rows: minmax(100px, auto);

     grid-gap: 20px;

     align-items: center;

     justify-items: start;

}

 .special {

     grid-column: 2 / 4;

     align-self: end;

     justify-self: end;

}

 .container > div {

     padding: 10px;

     background-color: rgba(111,41,97,.3);

     border: 2px solid rgba(111,41,97,.5);

}

example: Smashing Guide to Layout: Grid align-items, justify-items, align-self, justify-self on Codepen

https:///rachelandrew/pen/WJWKgd

align-contentjustify-content属性则会对网格中的行/列(tracks)进行对齐控制(网格容器中需要在排列完行/列元素后有多余的空间)。

div class='container'>

    div>1div>

    div>2div>

    div>3div>

    div>4div>

    div>5div>

div>

body {

     padding: 20px;

     font: 1em Helvetica Neue, Helvetica, Arial, sans-serif;

}

 {

    box-sizing: border-box;

}

 {

     margin: 0 0 1em 0;

}

 .container {

     width: 500px;

     height: 300px;

     border: 5px solid rgb(111,41,97);

     border-radius: .5em;

     padding: 10px;

     display: grid;

     grid-template-columns: 100px 100px 100px;

     grid-auto-rows: minmax(100px, auto);

     grid-gap: 20px;

     align-content: space-between;

     justify-content: end;

}

 .container > div {

     padding: 10px;

     background-color: rgba(111,41,97,.3);

     border: 2px solid rgba(111,41,97,.5);

}

example: Smashing Guide to Layout: Grid align-content, justify-content on Codepen

https:///rachelandrew/pen/mLgGym

在弹性盒子中,align-itemsalign-self用来解决交叉轴上的对齐问题,而justify-content则用于解决主轴上空间的分配。

div class='container'>

    div>1div>

    div>2div>

    div class='special'>3div>

    div>4div>

div>

body {

     padding: 20px;

     font: 1em Helvetica Neue, Helvetica, Arial, sans-serif;

}

 {

    box-sizing: border-box;

}

 {

     margin: 0 0 1em 0;

}

 .container {

     width: 500px;

     height: 300px;

     border: 5px solid rgb(111,41,97);

     border-radius: .5em;

     padding: 10px;

     display: flex;

     justify-content: space-between;

     align-items: flex-end;

}

 .special {

     align-self: stretch;

}

 .container > div {

     padding: 10px;

     background-color: rgba(111,41,97,.3);

     border: 2px solid rgba(111,41,97,.5);

}

example: Smashing Guide to Layout: Flex justify-content, align-items, align-self on Codepen

https:///rachelandrew/pen/ZoZMQZ

在交叉轴上,把弹性行(flex line)和额外空间包裹在弹性容器中之后,你就可以使用align-content了。

div class='container'>

    div>1div>

    div>2div>

    div>3div>

    div>4div>

    div>5div>

div>

{

     margin: 0 0 1em 0;

}

 .container {

     width: 500px;

     height: 300px;

     border: 5px solid rgb(111,41,97);

     border-radius: .5em;

     padding: 10px;

     display: flex;

     flex-wrap: wrap;

     align-content: space-between;

}

 .container > div {

     flex: 1 1 200px;

     padding: 10px;

     background-color: rgba(111,41,97,.3);

     border: 2px solid rgba(111,41,97,.5);

}

example: Smashing Guide to Layout: Flex align-content on Codepen

https:///rachelandrew/pen/QrPVjB

下面的一些链接更细节地讨论了各类布局方法中的盒模型对齐。花些时间去理解对齐的工作原理是非常值得的,它对理解弹性盒子、网格布局以及未来的一些布局方法都会很有帮助。

8.1 行/列的间隔

一个多栏布局具有column-gap属性,到目前位置,网格布局具有grid-column-gaogrid-row-gapgrid-grid。这些现在都被从grid标准中删除而被添加进盒模型对齐中了。与此同时,grid-的前缀属性被重命名为column-gaprow-gapgap。浏览器会将带有前缀的属性换为新的重命名属性,所以如果你在目前的代码中使用兼容性更好的老名字也不用担心。

重命名意味着这些属性也能被应用于其他布局方法,一个明显的备选就是弹性盒子。虽然目前没有浏览器支持盒子模型中的gap属性,但是在未来我们应该可以使用column-gaprow-gap来创建弹性项目元素间的间距。

8.2 关于box generation的其他阅读资料

  • “CSS Box Alignment,” CSS: Cascading Style Sheets, MDN web docs, Mozilla

  • “Box Alignment in Flexbox,” CSS Flexible Box Layout, MDN web docs, Mozilla

  • “Box Alignment in CSS Grid Layout,” CSS Grid Layout, MDN web docs, Mozilla

  • “The New Layout Standard For The Web: CSS Grid, Flexbox And Box Alignment,” Rachel Andrew, Smashing Magazine

  • “Box Alignment Cheatsheet,” Rachel Andrew

9. 多栏布局(多列布局)

多栏布局(multi-column layout)是一种支持创建多栏的布局类型,如同报纸上那样。每一块都被分割成栏(column),你会按照块方向在栏中往下读然后会在回到下一栏的顶部。然而用这种方式阅读在网页内容中并不总是有效,因为人们并不想去让滚动条滚动来、滚动去地去阅读。当需要展示少部分内容、折叠一组复选框或者其他一些小的UI组件时会非常有用。

当展示一组高度不同的卡片或产品时多栏布局也非常有用。

9.1 设置栏的宽度

要设置一个最有的栏宽,并通知浏览器依此宽度展示尽可能多的栏可以使用下面的CSS:

.container {

     column-width: 300px;

}

这会创建尽可能多的300px的栏,所有剩下的空间会被所有栏共享。因此,除非空间被划分为300px时没有剩余,否则你的栏会比300px稍多一些。

9.2 设置栏的数目

除了设置宽度,你可以使用column-count来设置栏的数目。在这种情况下,浏览器会将空间均分给你需要的数目的栏。

.container {

     column-count: 3;

}

如果你同时添加了column-widthcolumn-count,那么column-count属性会作为一个最大值限制。在下面的代码里,栏会被添加直到达到三个,此时任何额外的空间都会被分给三栏,即使空间足够成为一个额外的新栏。

.container {

     column-width: 300px;

     column-count: 3;

}

9.3 间距和栏规则

你无法为单个栏盒子添加外边距和内边距,需要用column-gap属性来设置间距。如果你不具体指定column-gap的值,它会默认为1em来防止栏间碰撞。这和其他布局方法中column-gap的行为不一样,其他布局中默认为0。你可以在间距上使用任意的长度单元,包括0(如果你不希望有栏间距)。

column-rule属性让你有能力向两栏间添加规则。它是column-rule-widthcolumn-rule-colorcolumn-rule-style的简写形式,可border行为类似。注意,一个规则自身不会占用任何空间。它会占据在间距的顶部,从而增加或减少那些你设置column-gap的规则与内容间的空间。

div class='container'>

    p>Pea horseradish azuki bean lettuce avocado asparagus okra. Kohlrabi radish okra azuki bean corn fava bean mustard tigernut jícama green bean celtuce. p>

    p>Grape silver beet collard greens avocado quandong fennel gumbo black-eyed pea watercress potato tigernut corn groundnut. Chickweed okra pea winter purslane coriander yarrow sweet pepper radish garlic brussels sprout groundnut summer purslane earthnut pea tomato spring onion azuki bean gourd. Gumbo kakadu plum komatsuna black-eyed pea green bean zucchini gourd winter purslane silver beet rock melon radish asparagus spinach.p>

div>

body {

     padding: 20px;

     font: 1em Helvetica Neue, Helvetica, Arial, sans-serif;

}

 {

    box-sizing: border-box;

}

 {

     margin: 0 0 1em 0;

}

 .container {

     width: 500px;

     border: 5px solid rgb(111,41,97);

     border-radius: .5em;

     padding: 10px;

     column-width: 120px;

     column-gap: 20px;

     column-rule: 4px dotted #000;

}

example: Smashing Guide to Layout: multicol on Codepen

https:///rachelandrew/pen/ELJdOQ

9.4 允许元素横跨多栏

你可以使用column-span属性让多栏容器内的元素横跨多栏,类似通栏。

h3 {

     column-span: all;

}

column-span出现时,多栏容器分栏会在这个元素上放停下,因此,容器里的内容会在元素上方形成多栏样式,然后在横跨元素(spanning element)的下方形成一组新的栏盒子(column box)。

div class='container'>

    p>Pea horseradish azuki bean lettuce avocado asparagus okra. Kohlrabi radish okra azuki bean corn fava bean mustard tigernut jícama green bean celtuce. p>

    h2>Veggies!h2>

    p>Grape silver beet collard greens avocado quandong fennel gumbo black-eyed pea watercress potato tigernut corn groundnut. Chickweed okra pea winter purslane coriander yarrow sweet pepper radish garlic brussels sprout groundnut summer purslane earthnut pea tomato spring onion azuki bean gourd. p>

div>

body {

     padding: 20px;

     font: 1em Helvetica Neue, Helvetica, Arial, sans-serif;

}

 {

    box-sizing: border-box;

}

 {

     margin: 0 0 1em 0;

}

 .container {

     width: 500px;

     border: 5px solid rgb(111,41,97);

     border-radius: .5em;

     padding: 10px;

     column-width: 120px;

     column-gap: 20px;

     column-rule: 4px dotted #000;

}

 .container h2 {

     column-span: all;

     background-color: rgba(193,225,237,.6);

     border:2px solid rgba(193,225,237,.6);

     margin: 1em 0;

     padding: .5em;

}

example: Smashing Guide to Layout: multicol span on Codepen

https:///rachelandrew/pen/gzyBQV

你只可以使用column-span: allcolumn-span: none,并不能让元素横跨某几个栏(非通栏)。在文章写作时,Firefox还不支持column-span属性。

9.5 关于多栏布局的其他阅读资料

  • “Using Multi-Column Layouts,” CSS Multi-column Layout, MDN web docs, Mozilla

10. 碎片化(Fragmentation)

多栏布局是碎片化(fragmentation)的一个例子,页面内容会被拆分成栏。这和打印时内容被分到不同页非常类似。这个过程是碎片化规范(Fragmentation specification)处理的。这个规范包括了一些帮助控制内容切分的属性。

例如,如果你有一组置于多栏中的卡片,并且你想确保卡片不会被截为两半分到不同的栏,你可以使用break-inside属性的avoid值。考虑浏览器兼容性的因素,你也可能会想使用遗留的page-break-inside属性。

.card {

     page-break-inside: avoid;

     break-inside: avoid;

}

如果你想在heading元素后禁止断行,你可以使用break-after属性。

.container h2 {

     page-break-after: avoid;

     break-after: avoid;

}

这些属性可以被用在打印样式或多栏样式中。在下面的例子里,在多栏容器中的三个段落被拆分到了三栏之中。我为p元素设置了break-inside: avoid,这意味着每个多栏会在自己的栏中结束(即使这会使各栏长度不同)。

div class='container'>

    p>Pea horseradish azuki bean lettuce avocado asparagus okra. Kohlrabi radish okra azuki bean corn fava bean mustard tigernut jícama green bean celtuce. p>

    p>Grape silver beet collard greens avocado quandong fennel gumbo black-eyed pea watercress potato tigernut corn groundnut. Chickweed okra pea winter purslane coriander yarrow sweet pepper radish garlic brussels sproutp>

    p>Groundnut summer purslane earthnut pea tomato spring onion azuki bean gourd. Gumbo kakadu plum komatsuna black-eyed pea green bean zucchini gourd winter purslane silver beet rock melon radish asparagus spinach.p>

div>

body {

     padding: 20px;

     font: 1em Helvetica Neue, Helvetica, Arial, sans-serif;

}

 {

    box-sizing: border-box;

}

 {

     margin: 0 0 1em 0;

}

 .container {

     width: 500px;

     border: 5px solid rgb(111,41,97);

     border-radius: .5em;

     padding: 10px;

     column-width: 120px;

     column-gap: 20px;

     column-rule: 4px dotted #000;

}

 .container p {

     page-break-inside: avoid;

     break-inside: avoid;

}

example: Smashing Guide to Layout: multicol fragmentation on Codepen

https:///rachelandrew/pen/wjZYOK

10.1 关于碎片化的其他阅读资料

  • “A Guide To The State Of Print Stylesheets In 2018,” Rachel Andrew, Smashing Magazine

  • “Column Breaks,” QuirksMode.org

11. 如何选择布局类型?

大多数的网页会混合使用多种布局类型。各布局规范都准确定义了它们之间是如何相互作用的。例如,你可能会在网格布局的网格项中使用弹性布局。一些弹性容器可能具有定位属性或浮动。这些规范根据最优的布局方式已经包含了布局模型的混合使用。在这篇指南中,我尝试概述了这种布局类型的基本使用方式,来帮助你了解实现一个效果可能的最好方法。

然而,别害怕去运用多种方式来实现布局设计。担心你的选择会不会造成实际问题的情况比你想象中要少很多。所以请在开始就组织好你的文档结构,并且注意你文档内容的可视展示顺序。剩下的大部分工作就是在浏览器中试试你的布局方式是否符合预期。

原文:Getting Started With CSS Layout,感谢作者Rachel Andrew。

关于奇舞周刊

《奇舞周刊》是360公司专业前端团队「奇舞团」运营的前端技术社区。关注公众号后,直接发送链接到后台即可给我们投稿。


    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约