父容器设置min-height,子元素height百分比失效 / height: 100%失效尝试解决height: a
背景
自从之前改博客园主题发现设置了高度但是实际上不是那个高度后(min-height导致的),就很喜欢用min-height。这次为外部设置了min-height,使得内部子元素的百分比没生效,于是尝试解决。
情况
当时的情况有些复杂,我们用一段类似的代码来模拟这个情况。
<template>
<main id="main">
<div class="home">
<span class="testText">测试文字</span>
</div>
<div>-------------模拟后面的元素</div>
</main>
</template>
<style scoped>
#main {
box-sizing: border-box;
overflow: hidden;
background-color: greenyellow;
min-height: 100vh;
}
.home {
box-sizing: border-box;
height: 50%;
background-color: red;
}
.testText {
font-size: 2rem;
}
</style>
空白处是默认样式,不必关心,为了方便截图,我打开f12切换成了移动设备显示。
可以发现,home标签没有占据对应的百分比高度。
分析
说是分析其实也不太对,我看了一些别人的文章,原因如下:
我们通常认为子元素的高度百分比设置是基于父容器的高度的。但是这句话其实不对,子元素只是基于height,而不是实际高度,也就是说min-height对其造成不了影响。那么可以猜到,父容器#main只设置了min-height而没有设置height,那么height的值为auto,而auto的百分比是用不了的,于是百分比失效。
解决
解决之前,我们需要再次梳理一下自己的需求:
- 父容器高度不固定,且拥有最小高度(保底高度)
- 子元素需要使用百分比高度。(不一定是100%)
- 后面的元素要正常显示(位置正确)
这样一来,把父容器高度固定这条路就走不通了,放弃1去追求2无异于拆东墙补西墙。
那么有哪些解决方案呢?
绝对定位(错误版)
其实在尝试时,还出现了一些状况,由于我要测试非100%的情况,于是在home之后加了一个测试元素,然后试图使用padding-top来占用home本该占用的空间,使得测试元素的位置符合预期。 但是此时遇到了另一个问题,那就是,padding的百分比是基于自身宽度的,哪怕是top和bottom依然是基于宽度,这有些反直觉。
<template>
<main id="main">
<div class="home">
<span class="testText">测试文字</span>
</div>
<div>-------------模拟后面的元素</div>
</main>
</template>
<style scoped>
#main {
/* 添加的代码 */
position: relative;
padding-top: 50%;
box-sizing: border-box;
overflow: hidden;
background-color: greenyellow;
min-height: 100vh;
}
.home {
/* 添加的代码 */
position: absolute;
top: 0;
left: 0;
box-sizing: border-box;
height: 50%;
background-color: red;
}
.testText {
font-size: 2rem;
}
</style>
效果如下,显然不是我们想要的。
绝对定位(正确版)
思路也很简单,既然绝对定位能够解决百分比问题,但是解决不了空间占用的问题,那么我们直接避开空间占用问题,使用程序设计中一种非常常见的操作——“套娃”。我们直接在home外部套一层wrapper,wrapper大小100%,然后home就能正常计算宽高了。
<template>
<main id="main">
<div class="wrapper">
<div class="home">
<span class="testText">测试文字</span>
</div>
<div>-------------模拟后面的元素</div>
</div>
</main>
</template>
<style scoped>
#main {
/* 添加的代码 */
position: relative;
box-sizing: border-box;
overflow: hidden;
background-color: greenyellow;
min-height: 100vh;
}
.wrapper {
position: absolute;
height: 100%;
width: 100%;
}
.home {
box-sizing: border-box;
height: 50%;
background-color: red;
}
.testText {
font-size: 2rem;
}
</style>
效果如下
原理
绝对定位元素与普通元素的计算方式不同,简单来说就是,普通元素使用百分比时参考的并不是父级元素的实际高度,因此经常会失效(auto时)。
grid
grid容器默认情况下,倾向于让子元素占满其内部空间
<template>
<main id="main">
<div class="wrapper">
<div class="home">
<span class="testText">测试文字</span>
</div>
<div>-------------模拟后面的元素</div>
</div>
</main>
</template>
<style scoped>
#main {
/* 添加的代码 */
display: grid;
box-sizing: border-box;
overflow: hidden;
background-color: greenyellow;
min-height: 100vh;
}
.home {
box-sizing: border-box;
height: 50%;
background-color: red;
}
.testText {
font-size: 2rem;
}
</style>
flex的align-items: stretch;
flex: 1可以占满剩余空间。 flex的侧轴默认情况下为stetch,从而避开了使用百分比的问题。
如果给wrapper设置个百分比,反而会失效。
虽然我们避开了百分比,但是我们的子元素依然要使用百分比,于是按照相同的套路,我们开始套娃。
<template>
<main id="main">
<div class="wrapper">
<div class="home">
<span class="testText">测试文字</span>
</div>
<div>-------------模拟后面的元素</div>
</div>
</main>
</template>
<style scoped>
#main {
/* 添加的代码 */
display: flex;
box-sizing: border-box;
overflow: hidden;
background-color: greenyellow;
min-height: 100vh;
}
.wrapper {
flex: 1;
}
.home {
box-sizing: border-box;
height: 50%;
background-color: red;
}
.testText {
font-size: 2rem;
}
</style>
结语
虽然遇到问题时多少有些懊恼,但是最终还是解决了,学到了新的东西还是很开心的。 这三种方式template部分基本相同,硬要说的话,grid方案的wrapper类名可以不写(但是html标签要保留)。 grid方案写起来是最简单的,可读性也是最差的;相比之下绝对定位的方案可读性是最好的但是也是最麻烦的。没有太过明显的优劣,喜欢哪个用哪个即可。
标题图片生成器
虽然不是我写的,但是用一用应该没什么问题。 logo.bluearchive.cc/
转载自:https://juejin.cn/post/7409138396792930338