如果兩個或多個元素很接近,那么用戶就會認為它們以某種方式屬于彼此。當對多個設計元素進行分組時,用戶可以根據它們之間的空間大小來決定它們之間的關系。沒有間距,用戶將很難瀏覽頁面并知道哪些內容相關而哪些內容無關。
在本文中,我將介紹有關CSS中的間距,實現此間距的不同方法以及何時使用 padding 或 margin 所需的所有知識。
更多的CSS知識點實踐相關文章,請見本篇文章底部
CSS中的間距有兩種類型,一種在元素外部,另一種在元素內部。對于本文,我將其稱為outer和inner。假設我們有一個元素,它內部的間距是inner,外部的間距是outer。
在CSS中,間距可以如下:
.element {
padding: 1rem;
margin-bottom: 1rem;
}
我使用 padding 來填充內部間距,使用 margin 來填充外部間距。很簡單,不是嗎?但是,當處理具有許多細節和子元素的組件時,這會變得越來越復雜。
它用于增加元素之間的間距。例如,在上一個示例中,我添加了 margin-bottom:1rem 在兩個堆疊的元素之間添加垂直間距。
由于可以沿四個不同的方向(top、right、 bottom、left)添加margin,因此在深入研究示例和用例之前,一定要闡明一些基本概念,這一點很重要。
簡而言之,當兩個垂直元素具有margin,并且其中一個元素的margin大于另一個元素時,發生邊距折疊。在這種情況下,將使用更大的margin,而另一個將被忽略。
在上面的模型中,一個元素有 margin-bottom,另一個元素有 margin-top,邊距較大的元素獲勝。
為避免此類問題,建議按照本文使用單向邊距。此外,CSS Tricks還在頁邊距底部和頁邊距頂部之間進行了投票。61%的開發者更喜歡 margin-bottom 而不是 margin-top。
請在下面查看如何解決此問題:
.element:not(:last-child) {
margin-bottom: 1rem;
}
使用 :not CSS選擇器,您可以輕松地刪除最后一個子元素的邊距,以避免不必要的間距。
另一個與邊距折疊相關的例子是子節點和父節點。讓我們假設如下:
<div class="parent">
<div class="child">I'm the child element</div>
</div>
.parent {
margin: 50px auto 0 auto;
width: 400px;
height: 120px;
}
.child {
margin: 50px 0;
}
請注意,子元素固定在其父元素的頂部。那是因為它的邊距折疊了。根據W3C,以下是針對該問題的一些解決方案:
一個更直接的解決方案是將 padding-top 添加到父元素。
它可以與四個方向一起使用以留出余量,在某些用例中非常有用。讓我們假設以下內容:
父節點具有 padding:1rem,這導致子節點從頂部、左側和右側偏移。但是,子元素應該緊貼其父元素的邊緣。負margin可以助你一臂之力。
.parent {
padding: 1rem
}
.child {
margin-left: -1rem;
margin-right: -1rem;
margin-top: -1rem;
}
如果您想更多地挖負margin,建議閱讀這篇文章。
如前所述,padding在元素內部增加了一個內間距。它的目標可以根據使用的情況而變化。
例如,它可以用于增加鏈接之間的間距,這將導致鏈接的可點擊區域更大。
必須提出的是,垂直方向的padding對于那些具有 display:inline 的元素不適用,比如 <span> 或 <a>。如果添加了內邊距,它不會影響元素,內邊距將覆蓋其他內聯元素。
這只是一個友好的提醒,應該更改內聯元素的 display 屬性。
.element span {
display: inline-block;
padding-top: 1rem;
padding-bottom: 1rem;
}
在CSS網格中,可以使用 grid-gap 屬性輕松在列和行之間添加間距。這是行和列間距的簡寫。
.element {
display: grid;
grid-template-columns: 1fr 1fr;
grid-gap: 16px; /* 為行和列都增加了16px的間隙。 */
}
gap屬性可以使用如下:
.element {
display: grid;
grid-template-columns: 1fr 1fr;
grid-row-gap: 24px;
grid-column-gap: 16px;
}
gap 是一個提議的屬性,將用于CSS Grid和flexbox,撰寫本文時,它僅在Firefox中受支持。
.element {
display: flex;
flex-wrap: wrap;
gap: 16px;
}
它可能不是直接的元素間距方式,但在一些設計案例中卻起到了一定的作用。例如,一個絕對定位的元素需要從其父元素的左邊緣和上邊緣定位 16px。
考慮以下示例,帶有圖標的卡片,其圖標應與其父對象的左上邊緣隔開。在這種情況下,將使用以下CSS:
.category {
position: absolute;
left: 16px;
top: 16px;
}
在這一節中,你將回顧一下在日常工作中,你在處理CSS項目時,會遇到的不同用例。
在這種情況下,標題具有logo,導航和用戶個人資料。你能猜出CSS中的間距應該如何設置嗎?好吧,讓我為你添加一個骨架模型。
<header class="c-header">
<h1 class="c-logo"><a href="#">Logo</a></h1>
<div class="c-header__nav">
<nav class="c-nav">
<ul>
<li><a href="#">...</a></li>
</ul>
</nav>
<a href="#" class="c-user">
<span>Ahmad</span>
<img class="c-avatar" src="shadeed.jpg" alt="">
</a>
</div>
</header>
Header的左側和右側都有padding,這樣做的目的是防止內容物緊貼在邊緣上。
.c-header {
padding-left: 16px;
padding-right: 16px;
}
對于導航,每個鏈接在垂直和水平側均應具有足夠的填充,因此其可單擊區域可以很大,這將增強可訪問性。
.c-nav a {
display: block;
padding: 16px 8px;
}
對于每個項目之間的間距,您可以使用 margin 或將 <li> 的 display 更改為 inline-block。內聯塊元素在它的兄弟元素之間添加了一點空間,因為它將元素視為字符。
.c-nav li {
/* 這將創建你在骨架中看到的間距 */
display: inline-block;
}
最后,頭像(avatar)和用戶名的左側有一個空白。
.c-user img,
.c-user span {
margin-left: 10px;
}
請注意,如果你要構建多語言網站,建議使用如下所示的CSS邏輯屬性。
.c-user img,
.c-user span {
margin-inline-start: 1rem;
}
請注意,分隔符周圍的間距現在相等,原因是導航項沒有特定的寬度,而是具有padding。結果,導航項目的寬度基于其內容。以下是解決方案:
最簡單,更好的解決方案是第三個解決方案,即添加 margin-left。
.c-user {
margin-left: 8px;
}
網格是間隔最常用的情況之一。考慮以下示例:
間距應在列和行之間。考慮以下HTML標記:
<div class="wrapper">
<div class="grid grid--4">
<div class="grid__item">
<article class="card"><!-- Card content --></article>
</div>
<div class="grid__item">
<article class="card"><!-- Card content --></article>
</div>
<!-- And so on.. -->
</div>
</div>
通常,我更喜歡將組件封裝起來,并避免給它們增加邊距。由于這個原因,我有 grid__item元素,我的card組件將位于其中。
.grid--4 {
display: flex;
flex-wrap: wrap;
}
.grid__item {
flex-basis: 25%;
margin-bottom: 16px;
}
使用上述CSS,每行將有四張卡片。這是在它們之間添加空格的一種可能的解決方案:
.grid__item {
flex-basis: calc(25% - 10px);
margin-left: 10px;
margin-bottom: 16px;
}
通過使用CSS calc() 函數,可以從 flex-basis 中扣除邊距。如你所見,這個方案并不是那么簡單。我比較喜歡的是下面這個辦法。
幾年前,我從CSS Wizardy那里學到了上述解決方案(我忘記了文章標題,如果您知道,請告訴我)。
.grid--4 {
display: flex;
flex-wrap: wrap;
margin-left: -10px;
}
.grid__item {
flex-basis: 25%;
padding-left: 10px;
margin-bottom: 16px;
}
我之所以用了負 margin-left,是因為第一張卡有 padding-left,而實際上不需要。所以,它將把 .wrapper 元素推到左邊,取消那個不需要的空間。
另一個類似的概念是在兩邊都添加填充,然后邊距為負。這是Facebook故事的一個示例:
.wrapper {
margin-left: -4px;
margin-right: -4px;
}
.story {
padding-left: 4px;
padding-right: 4px;
}
現在,到了激動人心的部分!使用CSS Grid,你可以很容易地使用 grid-gap 添加間距。此外,你不需要關心網格項的寬度或底部空白,CSS Grid 為你做這一切!
.grid--4 {
display: grid;
grid-template-columns: 1fr 1fr 1fr;
grid-gap: 1rem;
}
就是這樣!難道不是那么容易和直接嗎?
我真正喜歡CSS Grid 的地方是 grid-gap 只在需要的時候才會被應用。考慮下面的模型。
沒有CSS網格,就不可能擁有這種靈活性。首先,請參見以下內容:
.card:not(:last-child) {
margin-bottom: 16px;
}
@media (min-width: 700px) {
.card:not(:last-child) {
margin-bottom: 0;
margin-left: 1rem;
}
}
不舒服吧?這個如何?
.card-wrapper {
display: grid;
grid-template-columns: 1fr;
grid-gap: 1rem;
}
@media (min-width: 700px) {
.card-wrapper {
grid-template-columns: 1fr 1fr;
}
}
完成了!容易得多。
假設以下組件堆疊在一起,每個組件都有底邊距。
注意最后一個元素有一個空白,這是不正確的,因為邊距只能在元素之間。
可以使用以下解決方案之一解決此問題:
解決方案1-CSS :not 選擇器
.element:not(:last-child) {
margin-bottom: 16px;
}
解決方案2:相鄰兄弟組合器
.element + .element {
margin-top: 16px;
}
雖然解決方案1具有吸引力,但它具有以下缺點:
關于解決方案2,它沒有CSS特異性問題。但是,它只能處理一個列棧。
更好的解決方案是通過向父元素添加負邊距來取消不需要的間距。
.wrapper {
margin-bottom: -16px;
}
它用一個等于底部間距的值將元素推到底部。注意不要超過邊距值,因為它會與同級元素重疊。
Oh,如果我想把所有細節的Card組件間距都寫進去的話,最后可能會出現書本上的內容。我就突出一個大概的模式,看看間距應該如何應用。
你能想到此卡片在哪里使用間距嗎?參見下圖。
<article class="card">
<a href="#">
<div class="card__thumb"><img src="food.jpg" alt=""></div>
<div class="card__content">
<h3 class="card__title">Cinnamon Rolls</h3>
<p class="card__author">Chef Ahmad</p>
<div class="card__rating"><span>4.9</span></div>
<div class="card__meta"><!-- --></div>
</div>
</a>
</article>
.card__content {
padding: 10px;
}
上面的 padding 將向其中的所有子元素添加一個偏移量。然后,我將添加所有邊距。
.card__title,
.card__author,
.card__rating {
margin-bottom: 10px;
}
對于評分和 .car__meta 元素之間的分隔線,我將添加它作為邊框。
.card__meta {
padding-top: 10px;
border-top: 1px solid #e9e9e9;
}
糟糕!由于對父元素 .card__content 進行了填充,因此邊框沒有粘在邊緣上。
是的,你猜對了!負邊距是解決辦法。
.card__meta {
padding-top: 10px;
border-top: 1px solid #e9e9e9;
margin: 0 -10px;
}
糟糕,再次!出了點問題。內容站在邊緣!
為了解決這個問題,內容應該從左右兩邊加點(呵呵,看來加點是個新詞)。
.card__meta {
padding: 10px 10px 0 10px;
border-top: 1px solid #e9e9e9;
margin: 0 -10px;
}
我相信這是一個非常非常普遍的用例。由于文章內容來自CMS(內容管理系統),或者是由Markdown文件自動生成的,因此無法為元素添加類。
考慮下面的示例,其中包含標題,段落和圖像。
<div class="wrapper">
<h1>Spacing Elements in CSS</h1>
<p><!-- content --></p>
<h2>Types of Spacing</h2>
<img src="spacing-1.png" alt="">
<p><!-- content --></p>
<p><!-- content --></p>
<h2>Use Cases</h2>
<p><!-- content --></p>
<h3>Card Component</h3>
<img src="use-case-card-2.png" alt="">
</div>
為了使它們看起來不錯,間距應保持一致并謹慎使用。我從type-scale.com借了一些樣式。
h1, h2, h3, h4, h5 {
margin: 2.75rem 0 1.05rem;
}
h1 {
margin-top: 0;
}
img {
margin-bottom: 0.5rem;
}
如果一個 <p> 后面有一個標題,例如“Types of Spacing”,那么 <p> 的 margin-bottom 將被忽略。你猜到了,那是因為頁邊距折疊。
我喜歡把這個叫做 "Just in case" margin,因為這就是字面意思。考慮一下下面的模型圖。
當元素靠近的時候,它們看起來并不好看。我是用flexbox搭建的。這項技術稱為“對齊移位包裝”,我從CSS Tricks中學到了它的名稱。
.element {
display: flex;
flex-wrap: wrap;
}
當視口尺寸較小時,它們的確以新行結尾。見下文:
需要解決的是中間設計狀態,即兩件物品仍然相鄰,但兩件物品之間的間距為零的設計狀態。在這種情況下,我傾向于向元素添加一個 margin-right,這樣可以防止它們相互接觸,從而加快 flex-wrap 的工作速度。
根據MDN:
writing-mode CSS屬性設置了文本行是水平還是垂直排列,以及塊的前進方向。
你是否曾經考慮過將邊距與具有不同 writing-mode 的元素一起使用時應如何表現?考慮以下示例。
.wrapper {
/* 使標題和食譜在同一行 */
display: flex;
}
.title {
writing-mode: vertical-lr;
margin-right: 16px;
}
標題被旋轉了90度,在它和圖像之間應該有一個空白區。結果表明,基于 writing-mode 的頁邊距工作得非常好。
我認為這些用例就足夠了。讓我們繼續一些有趣的概念!
大型設計系統包含許多組件。向其直接添加邊距是否合乎邏輯?
考慮以下示例。
<button class="button">Save Changes</button>
<button class="button button-outline">Discard</button>
按鈕之間的間距應在哪里添加?是否應將其添加到左側或右側按鈕?也許你可以如下使用相鄰同級選擇器:
.button + .button {
margin-left: 1rem;
}
這是不好的。如果只有一個按鈕的情況怎么辦?或者,當它垂直堆疊時在移動設備上將如何工作?很多很多的復雜性。
解決上述問題的一種方法是使用抽象的組件,其目標是托管其他組件,就像Max Stoiber所說的那樣,這是將管理邊距的責任移到了父元素上,讓我們以這種思維方式重新思考以前的用例。
<div class="list">
<div class="list__item">
<button class="button">Save Changes</button>
</div>
<div class="list__item">
<button class="button button-outline">Discard</button>
</div>
</div>
注意,我添加了一個包裝器,并且每個按鈕現在都包裝在其自己的元素中。
.list {
display: flex;
align-items: center;
margin-left: -1rem; /* 取消第一個元素的左空白 */
}
.list__item {
margin-left: 1rem;
}
就是這樣!而且,將這些概念應用到任何JavaScript框架中都相當容易。例如:
<List>
<Button>Save Changes</Button>
<Button outline>Discard</Button>
</List>
你使用的JavaScript工具應該將每個項包裝在自己的元素中。
是的,你沒看錯。我在這篇文章中討論了避免margin的概念,并使用間隔組件來代替它們。
讓我們假設一個區域需要從左到右24px的空白,并記住這些限制:
我在檢查Facebook的新設計CSS時首先注意到了這一點。
那是一個 <div>,內聯樣式寬度:16px,它唯一的作用是在左邊緣和包裝器之間增加一個空白空間。
引述這本React游戲手冊中的內容。
但在現實世界中,我們確實需要組件之外的間距來合成頁面和場景,這就是margin滲入組件代碼的地方:用于組件的間距組合。
我同意。對于大型設計系統,不斷向組件添加margin是不可伸縮的。這將最終導致一個令人毛骨悚然的代碼。
現在你了解了間隔組件的概念,讓我們深入研究使用它們時遇到的一些挑戰。這是我想到的一些問題:
讓我們一一解決上述問題。
可以創建一個接受不同變化和設置的間隔。我不是JavaScript開發人員,但我認為他們將其稱為Props。考慮來自styled-system.com的以下內容:
我們在一個header和一個 section之間有一個隔板。
<Header />
<Spacer mb={4} />
<Section />
雖然這個有點不一樣,一個間隔器在logo和導航之間建立一個自動間隔。
<Flex>
<Logo />
<Spacer m="auto" />
<Link>Beep</Link>
<Link>Boop</Link>
</Flex>
你可能會認為,通過添加 justify-content:space-between,使用CSS做到這一點相當容易。
如果設計上需要改一下怎么辦?那么,如果是這樣的話,樣式就應該改了。
見下文,你看到那里的靈活性了嗎?
<Flex>
<Logo />
<Link>Beep</Link>
<Link>Boop</Link>
<Spacer m="auto" />
<Link>Boop</Link>
</Flex>
那么,如果是這樣的話,就應該改變樣式。你看出來有什么靈活性了嗎?對于尺寸調整部分,可以根據其母體的尺寸調整間隔的尺寸。
對于上面的內容,也許你可以做一個叫 grow 的prop,可以計算成 flex-grow:1 在CSS中。
<Flex>
<Spacer grow="1" />
</Flex>
我考慮過的另一個想法是使用偽元素創建間隔符。
.element:after {
content: "";
display: block;
height: 32px;
}
也許我們可以選擇通過一個偽元素而不是一個單獨的元素來添加間隔器?例如:
<Header spacer="below" type="pseudo" length="32">
<Logo />
<Link>Home</Link>
<Link>About</Link>
<Link>Contact</Link>
</Header>
直到今天,我還沒有在項目中使用間隔組件,但是我期待可以使用它們的用例。
有可能有動態的邊距嗎?例如,根據視口寬度設置具有最小值和最大值的空白。答案是肯定的!我們可以。最近,Firefox 75支持CSS數學函數,這意味著根據CanIUse在所有主流瀏覽器中都支持CSS數學函數。
讓我們回想一下Grid用例,以了解如何在其中使用動態間距。
.wrapper {
display: grid;
grid-template-columns: repeat(3, 1fr);
grid-gap: min(2vmax, 32px);
}
下面是 min(2vmax,32px) 的意思:使用一個等于 2vmax 的間隙,但不能超過 32px。
擁有這樣的靈活性確實令人驚訝,并且為我們提供了構建更多動態和靈活布局的許多可能性。
你不知道的CSS國際化「實踐」
手把手整理CSS3知識匯總【思維導圖】
手把手教你55 個提高CSS 開發效率的必備片段
手把手教你常見的CSS布局方式【實踐】
讓CSS flex布局最后一行左對齊的N種方法
妙用CSS變量,讓你的CSS變得更心動
純CSS實現簡單骨骼動畫【實踐】
CSS揭秘實用技巧總結
你未必知道的49個CSS知識點
深入淺出超好用的 CSS 陰影技巧
關于前端CSS寫法104個知識點匯總(一)
關于前端CSS寫法104個知識點匯總(二)
前端開發規范:命名規范、html規范、css規范、js規范
CSS變量實現暗黑模式,我的小鋪頁面已經支持
深入淺出CSS中徹底搞懂word-break、word-wrap、white-space
深入淺出詳細講解CSS 渲染原理以及優化策略
手把手教你深入CSS實現一個粒子動效的按鈕
手把手教你css 中多種邊框的實現小竅門【實踐】
手把手詳細教你優化CSS提高網站加載速度的21種方法匯總【實踐】
、HTML5設計哲學,它并不是規范優先的設計,它是“妥協式”的規范。
2、HTML5對元素大小寫不再嚴格區分,開發者可以隨意使用大小寫字符來定義HTML元素。
3、對于一份基本的HTML5文檔而言,它總有如下結構:
<!DOCTYPE html>
<html>
<head>
<title>頁面標題</title>
<meta http-equiv=”Content-Type” content=”text/html; charset=gb2312”/>
<!—此處還可插入其他meta、樣式單等信息à
</head>
<body>
頁面內容部分
</body>
</html>
4、不要在<html>和<head>之前插入任何內容!不要在</head>和<body>之間插入任何內容!不要在</body>和</html>之前插入任何內容。
5、HTML5保留的基本元素有如下幾個:
<!--…-->:定義HTML注釋,里面的內容會被當成注釋處理。
<html>:它是HTML5文檔的根元素。但HTML5允許完全省略這個元素。
<head>:它用于定義HTML5文檔的頁面頭部分。但HTML5允許完全省略這個元素。
<title>:用于定義HTML5文檔的頁面標題。
<body>:用于定義HTML5文檔的頁面主體部分,該標簽可以指定id、class、style等核心屬性,還可以指定onload、onunload、onclick、ondblclick、onmousedown、onmouseup、onmouseover、onmousemove、onmouseout、onkeypress、onkeydown、onkeyup等事件屬性,這些屬性用于指定JavaScript腳本。
6、幾乎所有的HTML元素都可指定id、style和class屬性。其中ID屬性用于為HTML元素指定一個唯一標識,該標識是通過DOM訪問HTML元素的重要途徑。Class 和style屬性是CSS樣式相關屬性。
7、<span>and <div>這兩個標簽很相像,只是前者默認是不會自動換行。使用的屬性值基本一樣。
8、<span/>、<div/>和<p/>三個元素都可以作為其他內容的“容器”,在默認情況下,<span/>不會導致換行,<div/>會導致換行,<p/>會產生出段落,段落之間會有更大的間距。更要注意的是<span/>和<p/>只能包含文本、圖像、超鏈接、文本格式化元素和表單控件等內容,<p/>可以<span/>,但<span/>不能包含<p/>;<div/>元素除了可以包含上面的這些內容外,還可以包含更多的元素。
9、<b>定義粗體,<i>定義斜體,<em>定義強調文本,<strong>定義粗體文本,在HTML5中,使用<strong.../>包起來的文本代表首重要的文本。<small>定義小號字體文本,在HMTL5中專門用于標識所謂的“小字印刷體”,通常用來標注諸如免責聲明、注意事項、法律規定和版權相關的聲明性文字。
10、<sup>定義上標文本,<sub>定義下標文本;<bdo>定義文本顯示的方向,該標簽也可以指定dir屬性,該屬性值只能是ltr或者rtl。
11、在HTML5中,空元素標簽不允許將開始標簽和結束標簽分開定義。空標簽有如下:area base br col command embed hr img input keygen link mata param source wbr。如果這些標簽開始和結束標簽分開寫是錯誤的。
12、可以省略結束標簽的元素:colgroup dt dd li optgroup option p rt rp thead tbody tfoot tr td th <p>
13、可以省略全部標簽的元素: html head body tbody。
*請認真填寫需求信息,我們會在24小時內與您取得聯系。