手记

一道《九宫格》题目考察你的CSS基本功

题目

实现这样的一个九宫格(300 x 300),鼠标hover的时候边框高亮

分析

主要涉及几个方面:

  1. 布局
  2. 盒模型
  3. 格与格之间的边框处理
  4. 边框的层叠问题
实践

布局上我们可以采用float、inline-block、table-cell、flex、grid等

这里以Flex布局为例

我们先创建一个九宫格,再来逐步完善细节

先创建九宫格

<ul class="grid">
  <li>1</li>
  <li>2</li>
  <li>3</li>
  <li>4</li>
  <li>5</li>
  <li>6</li>
  <li>7</li>
  <li>8</li>
  <li>9</li>
</ul>
html,body,ul,li {
  padding: 0;
  margin: 0;
}
ul {
  list-style: none;
}
.grid {
  width: 300px;
  display: flex;
  flex-wrap: wrap;  // 设置换行,才能实现一个九宫格
}
.grid li {
  width: 100px;
  height: 100px;
  border: 4px solid #000000;
  text-align: center;          // 文字水平居中
  line-height: 100px;          // 文字垂直居中      
  box-sizing: boder-box;       // 设置盒模型
}

这样我们实现了一个九宫格,其中注意设置flex-wrap: wrap;box-sizing: boder-box;

flex-wrap属性默认nowrap,表示不拆行不拆列,如果我们不设置,会发现9个格子都挤在同一行,无法实现九宫格,所以设置为warp,表示在必要时候可拆行或拆列

box-sizing涉及盒模型相关知识,默认取值是content-box,表示元素width的值为contentwidth,不包括paddingborder,设置为boder-box则表示元素width的值为content+padding+border

例如我们这里不设置box-sizing,可知九宫格容器宽为300px,一个格子宽设为100px,边框为4px,那么一个格子总宽就为108px,三个格子则需要324px,此时第三个格子就会被换行移动至第二行,此时需要把格子宽设置为92px才能实现一个九宫格,如果边框大小变动,又得重新计算格子宽度,比较麻烦,所以我们设置为boder-box则方便许多

解决边框问题

只要视力没问题的,应该都看得出上面创建的九宫格中,格子与格子直接的边框并不符合我们的要求,我们可以采用“负边距”方法来解决,简单理解就是第二列和第三列的格子往左移动一个边框大小,第二行和第三行的格子往上移动一个边框大小,第一列和第一行不动

直接上代码

.grid li {
  width: 100px;
  height: 100px;
  border: 4px solid #000000;
  text-align: center;          // 文字水平居中
  line-height: 100px;          // 文字垂直居中      
  box-sizing: boder-box;       // 设置盒模型

  // 以下为新增代码
  margin-left: -4px;
  margin-top: -4px;
}

// 以下为新增代码
.gird li:nth-child(3n+1) {     // 表示第1、4、7个格子
  margin-left: 0;
}

.grid li:nth-child(-n+3) {     // 表示前3个格子 
  margin-top: 0;
}

这里涉及到的知识点是利用负边距来解决边框问题,以及CSS的高级选择器:nth-child(n)

:nth-child(n)选择器表示匹配属于其父元素的第n个子元素,不论元素的类型,n的取值可以是数字、关键词或者公式,注意公式的格式是an+bn是计数器,从0开始,b是偏移量

比如:
:nth-child(2)表示取其父元素中的第2个子元素
:nth-child(odd)表示取其父元素中下标为奇数的子元素(第一个子元素是1)
:nth-child(even)表示取其父元素中下标为偶数的子元素(第一个子元素是1)
:nth-child(3n+0)表示取其父元素中下标为是3的倍数的子元素(n从0开始算起)

加上hover效果

鼠标移上去使对应格子边框红色高亮

.grid li:hover {
  boder-color: red;
}

加上之后查看效果:

解决边框重叠问题

加上hover效果之后发现边框被重叠,可以通过设置z-index来解决

.grid li:hover {
  boder-color: red;

  // 以下为新增代码
  z-index: 2;
}

最终得到我们想要的九宫格

其他布局

基本大同小异,这里提供其他布局的代码及注释

使用float

<ul class="grid">
  <li>1</li>
  <li>2</li>
  <li>3</li>
  <li>4</li>
  <li>5</li>
  <li>6</li>
  <li>7</li>
  <li>8</li>
  <li>9</li>
</ul>
html,body,ul,li {
  padding: 0;
  margin: 0;
}
ul {
  list-style: none;
}
.grid {
  width: 300px;
  float: left;
}
.grid li {
  float: left;
  width: 100px;
  height: 100px;
  margin-left: -4px;
  margin-top: -4px;
  line-height: 100px;
  text-align: center;
  color: #444;
  border: 4px solid #444;
  position: relative;       // 为了让z-index起效果,需要加上这个
  box-sizing: border-box; 
}
.grid li:nth-child(3n+1) {
  margin-left: 0;
}
.grid li:nth-child(-n+3) {
  margin-top: 0;
}
.grid li:hover {
  border-color: red;
  z-index: 2;
}

grid

<ul class="grid">
  <li>1</li>
  <li>2</li>
  <li>3</li>
  <li>4</li>
  <li>5</li>
  <li>6</li>
  <li>7</li>
  <li>8</li>
  <li>9</li>
</ul>
html,body,ul,li {
  padding: 0;
  margin: 0;
}
ul {
  list-style: none;
}
.grid {
  width: 300px;
  display: grid;
  grid-template-columns: 100px 100px 100px; // 设置三列,每列100px
  grid-template-rows: 100px 100px 100px;    // 设置三行,每行100px
}
.grid li {
  text-align: center;
  line-height: 100px;
  border: 4px solid #000000;
  box-sizing: border-box;
  margin-left: -4px;
  margin-top: -4px;
}
.grid li:nth-child(3n+1) {
  margin-left: 0;
}
.grid li:nth-child(-n+3) {
  margin-top: 0;
}
.grid li:hover {
  border-color: red;
  z-index: 2;
}

inline-block

<ul class="grid">
  <li>1</li>
  <li>2</li>
  <li>3</li>
  <li>4</li>
  <li>5</li>
  <li>6</li>
  <li>7</li>
  <li>8</li>
  <li>9</li>
</ul>
html,body,ul,li {
  padding: 0;
  margin: 0;
}
ul {
  list-style: none;
}
.grid {
  width: 300px;
  font-size: 0;           // 消除inline-block元素间的空格
}
.grid li {
  width: 100px;
  height: 100px;
  display: inline-block;
  font-size: 16px;        // 父元素设置了0,这里需要重新设置一下
  text-align: center;
  line-height: 100px;
  border: 4px solid #000000;
  box-sizing: border-box;
  position: relative;     // 为了让z-index起效果,需要加上这个
  margin-left: -4px;
  margin-top: -4px;
}
.grid li:nth-child(3n+1) {
  margin-left: 0;
}

.grid li:nth-child(-n+3) {
  margin-top: 0;
}

.grid li:hover {
  border-color: red;
  z-index: 2;
}

table-cell

使用table布局,这里不知道有没有更好的方法

<ul class="grid">
  <li>
    <span>1</span>
    <span>2</span>
    <span>3</span>
  </li>
  <li>
    <span>4</span>
    <span>5</span>
    <span>6</span>
  </li>
  <li>
    <span>7</span>
    <span>8</span>
    <span>9</span>
  </li>
</ul>
html,body,ul,li {
  padding: 0;
  margin: 0;
}
ul {
  list-style: none;
}
.grid {
  width: 300px;
  display: table;
}
.grid li {
  display: table-row;
}
.grid li span {
  float: left;        // 因为table-cell会导致margin不起作用,所以加上这个才会起作用
  width: 100px;
  height: 100px;
  margin-left: -4px;
  margin-top: -4px;
  line-height: 100px;
  text-align: center;
  color: #444;
  border: 4px solid #444;
  display: table-cell;
  position: relative;   // 为了让z-index起效果,需要加上这个
  box-sizing: border-box; 
}
.grid li span:first-child { // 每个li内的第一个span
  margin-left: 0;
}
.grid li:first-child span { // 第一个li内的每个span
  margin-top: 0;
}
.grid li span:hover {
  border-color: red;
  z-index: 2;
}
结语

本人在写页面这方面算是新手,难免有错误,希望各位看官可以不吝赐教,共同进步。

5人推荐
随时随地看视频
慕课网APP

热门评论

写的不错,用jquery瀑布流的思想可以解决多少空格的都可以,m*n格

查看全部评论