小宋爱睡觉 小宋爱睡觉
首页
  • HTML
  • CSS
  • JavaScript
  • Vue
  • React
  • 计算机网络
  • 浏览器原理
  • 性能优化
  • 设计模式
手写系列
  • 字符串
  • 数组
  • 链表
  • 树
  • 动态规划
  • 排序算法
  • GitHub (opens new window)
  • JueJin (opens new window)
首页
  • HTML
  • CSS
  • JavaScript
  • Vue
  • React
  • 计算机网络
  • 浏览器原理
  • 性能优化
  • 设计模式
手写系列
  • 字符串
  • 数组
  • 链表
  • 树
  • 动态规划
  • 排序算法
  • GitHub (opens new window)
  • JueJin (opens new window)
  • CSS
  • 手写布局
  • 场景布局
    • 实现一个三角形
    • 实现一个等腰三角形
    • 实现一个等边三角形
    • 实现一个扇形
    • 实现一个自适应的正方形
    • 画一条0.5px的线
    • 设置小于12px的字体
    • 如何解决1px问题
  • CSS
Crucials
2021-11-27

场景布局

# 场景应用

# 实现一个三角形

三角1

div {
  width: 0;
  height: 0;
  border-top: 50px solid red;
  border-right: 50px solid transparent;
  border-left: 50px solid transparent;
}
1
2
3
4
5
6
7

img

三角2

div {
    width: 0;
    height: 0;
    border-bottom: 50px solid red;
    border-right: 50px solid transparent;
    border-left: 50px solid transparent;
}
1
2
3
4
5
6
7

img

三角3

div {
    width: 0;
    height: 0;
    border-left: 50px solid red;
    border-top: 50px solid transparent;
    border-bottom: 50px solid transparent;
}
1
2
3
4
5
6
7

img

三角4

div {
    width: 0;
    height: 0;
    border-right: 50px solid red;
    border-top: 50px solid transparent;
    border-bottom: 50px solid transparent;
}
1
2
3
4
5
6
7

img

三角5

div {
    width: 0;
    height: 0;
    border-top: 100px solid red;
    border-right: 100px solid transparent;
}
1
2
3
4
5
6

img

# 实现一个等腰三角形

div {
  width: 0px;
  height: 0px;
  border-left: 80px solid transparent;
  border-right: 80px solid transparent;
  border-bottom: 100px solid #333;
}
1
2
3
4
5
6
7

# 实现一个等边三角形

div {
  width: 0px;
  height: 0px;
  border-left: 100px solid transparent;
  border-right: 100px solid transparent;
  border-bottom: 173px solid #333;// 根号3倍的left/right
}
1
2
3
4
5
6
7

# 实现一个扇形

div{
    border: 100px solid transparent;
    width: 0;
    heigt: 0;
    border-radius: 100px;
    border-top-color: red;
}
1
2
3
4
5
6
7

img

# 实现一个自适应的正方形

  • 利用vw实现
.square {
  width: 10%;
  height: 10vw;
  background: tomato;
}
1
2
3
4
5

利用元素的margin/padding是相对父元素来实现

.square {
  width: 20%;
  height: 0;
  padding-top: 20%;
  background: orange;
}
1
2
3
4
5
6

利用子元素的margin-top实现

.square {
  width: 30%;
  overflow: hidden;
  background: yellow;
}
.square::after {
  content: '';
  display: block;
  margin-top: 100%;
}
1
2
3
4
5
6
7
8
9
10

# 画一条0.5px的线

  • 采用transform: scale()的方式,该方法用来定义元素的2D 缩放转换:
transform: scale(0.5,0.5);
1
  • 采用meta viewport的方式
<meta name="viewport" content="width=device-width, initial-scale=0.5, minimum-scale=0.5, maximum-scale=0.5"/>
1

这样就能缩放到原来的0.5倍,如果是1px那么就会变成0.5px。viewport只针对于移动端,只在移动端上才能看到效果

# 设置小于12px的字体

  • 使用css3的transform缩放属性-webkit-transform:scale(0.5); 注意-webkit-transform:scale(0.75);收缩的是整个元素的大小,这时候,如果是内联元素,必须要将内联元素转换成块元素,可以使用display:block/inline-block/...;
    • 使用图片:如果是内容固定不变情况下,使用将小于12px文字内容切出做图片,这样不影响兼容也不影响美观

# 如何解决1px问题

1px 问题

在一些 Retina屏幕 的机型上,移动端页面的 1px 会变得很粗,呈现出不止 1px 的效果。原因很简单——CSS 中的 1px 并不能和移动设备上的 1px 划等号。它们之间的比例关系有一个专门的属性来描述:

window.devicePixelRatio = 设备的物理像素 / CSS像素

打开 Chrome 浏览器,启动移动端调试模式,在控制台去输出这个 devicePixelRatio 的值。

这里选中 iPhone6/7/8 这系列的机型,输出的结果就是2:

img

这就意味着设置的 1px CSS 像素,在这个设备上实际会用 2 个物理像素单元来进行渲染,所以实际看到的一定会比 1px 粗一些。 解决1px 问题的三种思路:

# 思路一:直接写 0.5px

如果之前 1px 的样式这样写:

border:1px solid #333;
1

可以先在 JS 中拿到 window.devicePixelRatio 的值,然后把这个值通过 JSX 或者模板语法给到 CSS 的 data 里,达到这样的效果(这里用 JSX 语法做示范):

<div id="container" data-device={{window.devicePixelRatio}}></div>
1

然后就可以在 CSS 中用属性选择器来命中 devicePixelRatio 为某一值的情况,比如说这里尝试命中 devicePixelRatio 为2的情况:

#container[data-device="2"] {
  border:0.5px solid #333
}
1
2
3

直接把 1px 改成 1/devicePixelRatio 后的值,这是目前为止最简单的一种方法。这种方法的缺陷在于兼容性不行,IOS 系统需要8及以上的版本,安卓系统则直接不兼容。

# 思路二:伪元素先放大后缩小

这个方法的可行性会更高,兼容性也更好。唯一的缺点是代码会变多。

思路是先放大、后缩小:在目标元素的后面追加一个 ::after伪元素,让这个元素布局为 absolute 之后、整个伸展开铺在目标元素上

然后把它的宽和高都设置为目标元素的两倍,border值设为 1px。

接着借助 CSS 动画特效中的放缩能力,把整个伪元素缩小为原来的 50%

此时,伪元素的宽高刚好可以和原有的目标元素对齐,而 border 也缩小为了 1px 的二分之一,间接地实现了 0.5px 的效果。

代码如下:

#container[data-device="2"] {
  position: relative;
}
#container[data-device="2"]::after{
  position:absolute;
  top: 0;
  left: 0;
  width: 200%;
  height: 200%;
  content:"";
  transform: scale(0.5);
  transform-origin: left top;
  box-sizing: border-box;
  border: 1px solid #333;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

# 思路三:viewport 缩放来解决

这个思路就是对 meta 标签里几个关键属性下手:

<meta name="viewport" content="initial-scale=0.5, maximum-scale=0.5, minimum-scale=0.5, user-scalable=no">
1

这里针对像素比为2的页面,把整个页面缩放为了原来的1/2大小。这样,本来占用2个物理像素的 1px 样式,现在占用的就是标准的一个物理像素。

根据像素比的不同,这个缩放比例可以被计算为不同的值,用 js 代码实现如下:

const scale = 1 / window.devicePixelRatio;
// 这里 metaEl 指的是 meta 标签对应的 Dom
metaEl.setAttribute('content', `width=device-width,user-scalable=no,initial-scale=${scale},maximum-scale=${scale},minimum-scale=${scale}`);
1
2
3

这样解决了,但这样做的副作用也很大,整个页面被缩放了。这时 1px 已经被处理成物理像素大小,这样的大小在手机上显示边框很合适。但是,一些原本不需要被缩小的内容,比如文字、图片等,也被无差别缩小掉了。

总结

局部处理

  • meta标签中的 viewport属性 ,initial-scale 设置为 1
  • rem按照设计稿标准走,外加利用transform 的scale(0.5) 缩小一倍即可;

全局处理

  • mate标签中的 viewport属性 ,initial-scale 设置为 0.5
  • rem 按照设计稿标准走即可
上次更新: 2022/02/19, 22:25:17
手写布局

← 手写布局

Copyright © 2021-2025 粤ICP备2021165371号
  • 跟随系统
  • 浅色模式
  • 深色模式