Open zhangxinxu opened 4 years ago
.header {
height: 300px;
background: lightgray;
}
.content {
position: relative;
writing-mode: vertical-lr;
width:100%;
}
.nav-wrap{
writing-mode:horizontal-tb;
display: inline-block;
margin-top:-50%;
width:100%;
text-align: center;
}
.nav {
display:inline-block;
border: 10px solid #53bff5;
border-radius: 10px;
}
.other{
display: inline-block;
position:absolute;
writing-mode:horizontal-tb;
width:100%;
}
.crumb-ol {
display:flex;
flex-wrap: wrap;
margin: 0;
padding-left: 0;
list-style: none;
}
.crumb{
padding:20px;
}
.crumb-img {
display:block;
height: 60px;
width: 40px;
margin:auto;
margin-bottom: 20px;
background:lightgreen;
}
<div class="header"></div>
<div class="content">
<div class="nav-wrap">
<nav class="nav">
<ol class="crumb-ol">
<li class="crumb">
<img class="crumb-img" />
<span class="crumb-text">进口食品</span>
</li>
<li class="crumb">
<img class="crumb-img" />
<span class="crumb-text">进口食品</span>
</li>
<li class="crumb">
<img class="crumb-img" />
<span class="crumb-text">进口食品</span>
</li>
<li class="crumb">
<img class="crumb-img" />
<span class="crumb-text">进口食品</span>
</li>
</ol>
</nav>
</div>
<div class="other">其他元素需要跟着一起往上挪</div>
</div>
<div style="height: 200px;background: red;"></div>
<nav id="nav" class="nav"></nav>
<div style="height: 200px;background: red;"></div>
.nav {
display: flex;
flex-wrap: wrap;
width: 200px;
background: rgb(70, 119, 253);
}
.nav div {
padding: 5px;
}
const nav = document.getElementById("nav");
for (let i = 0; i < 10; i++) {
const div = document.createElement("div");
div.innerHTML = "test";
nav.appendChild(div);
}
nav.style.marginTop = `-${nav.offsetHeight / 2}px`;
<header></header>
<nav id="nav" class="nav"></nav>
<footer></footer>
div{
background-color: red;
}
header, nav, footer{
height: 10rem;
}
nav{
display: grid;
grid-template-columns: repeat(5, 1fr);
grid-gap: 1rem;
}
{
render(9)
function render(num){
let navEl = document.getElementById("nav");
let inner = [...".".repeat(num)].map(item => "<div></div>").join("");
navEl.innerHTML = inner;
navEl.style.marginTop = `-${navEl.offsetHeight / 2}px`;
}
}
<nav class="nav" id="nav">
<ul class="nav-wrap">
<li class="nav-wrap-item">
<i class="nav-wrap-item-icon"></i>
<span class="nav-wrap-item-title">进口食品</span>
</li>
<li class="nav-wrap-item">
<i class="nav-wrap-item-icon"></i>
<span class="nav-wrap-item-title">进口食品</span>
</li>
<li class="nav-wrap-item">
<i class="nav-wrap-item-icon"></i>
<span class="nav-wrap-item-title">进口食品</span>
</li>
<li class="nav-wrap-item">
<i class="nav-wrap-item-icon"></i>
<span class="nav-wrap-item-title">进口食品</span>
</li>
<li class="nav-wrap-item">
<i class="nav-wrap-item-icon"></i>
<span class="nav-wrap-item-title">进口食品</span>
</li>
<li class="nav-wrap-item">
<i class="nav-wrap-item-icon"></i>
<span class="nav-wrap-item-title">进口食</span>
</li>
</ul>
</nav>
<div id="navTop"></div>
body {
margin: 0;
font-family: sans-serif;
font-weight: 400;
font-size: 16px;
}
.nav {
margin:0 20px;
transform: translateY(-50%);
}
.nav-wrap {
display: flex;
flex-wrap: wrap;
justify-content: space-between;
margin: 0;
padding: 0;
border: 10px solid rgb(80, 190,250);
border-radius: 10px;
list-style: none;
background-color: #fff;
}
.nav-wrap-item {
flex-basis: 65px;
margin: 20px;
text-align: center;
white-space: nowrap;
overflow: hidden;
}
.nav-wrap-item-icon {
display: block;
width: 100%;
padding-top: 100%;
background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' class='octicon octicon-mark-github text-white' aria-hidden='true' viewBox='0 0 16 16' width='32' height='32'%3E%3Cpath fill-rule='evenodd' d='M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 7.59.4.07.55-.17.55-.38 0-.19-.01-.82-.01-1.49-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23.82.72 1.21 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82.64-.18 1.32-.27 2-.27.68 0 1.36.09 2 .27 1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 1.93-.01 2.2 0 .21.15.46.55.38A8.013 8.013 0 0 0 16 8c0-4.42-3.58-8-8-8z'/%3E%3C/svg%3E") no-repeat center;
background-size: 100%;
margin: 0 0 20px;
}
var nav = document.querySelector('.nav');
var navTop = document.querySelector('#navTop');
function resize() {
var navHalfHeight = parseFloat(getComputedStyle(nav).height) / 2;
if (parseFloat(navTop.style.marginTop) !== -navHalfHeight) {
navTop.style.marginTop = -navHalfHeight + 'px';
}
}
resize()
window.addEventListener('resize', resize);
查看demo : JSBIN
我的理解是,本题就是一个不定高的元素怎么往上移动高度的50%,且后续元素跟随。
能想到的思路是利用writing-mode: vertical-lr;
让 margin-top
基于高度去计算。可是发现margin-top
是百分比的时候元素并不会跟随,可是换成同样数值的固定值就可以。
不是很理解这个逻辑。所以并未实现。
看到 @liyongleihf2006 用
position:absolute;
的解法我震惊了,手动为他点赞
.banner {
padding-top: 30%;
background-color: rgba(255, 0, 0, 0.5);
}
.nav {
background-color: blue;
width: 92%;
margin: 0 auto;
writing-mode: vertical-lr;
}
.nav-in{
display: inline-block;
width: 100%;
background-color: rgba(0,255, 0, 0.5);
height: 80px;
}
.nav-in{
margin-top: -50%; /* 不理解为啥后面元素不跟随 */
}
#nav2 .nav-in{
margin-top: -40px; /* 这样就可以 */
}
<section class="banner"></section>
<nav id="nav" class="nav">
<div class="nav-in"></div>
</nav>
我是其它的文案1
<section class="banner"></section>
<nav id="nav2" class="nav">
<div class="nav-in"></div>
</nav>
我是其它的文案2
@ziven27
margin
当单位是%
的时候是相对于包含快的宽度来进行计算的,也就是说
.nav-in{
margin-top: -50%; /* 不理解为啥后面元素不跟随 */
}
里面的margin-top
实际是按照.nav
的宽度来进行计算的。
又因为.nav
使用了writing-mode: vertical-lr;
属性,所以实际值是按照.nav
的高度来进行计算的。而.nav
的高度是被.nav-in
撑开的,所以.nav
是有一个高度值的,这个值就是.nav-in
的高度。
最终即使.nav-in
因为margin-top
上移了,之后的其他文案也没有跟随,因为.nav
已经有了一个高度占位了。
拙见,不知道我理解的对不对。
第一眼还以为是CSS
基础测试题,结果就奔着纯CSS
去了;想半天卡壳了,回来一看居然是DOM
测试题……
@后话:本来以为纯CSS没有办法,评论区果然打脸了;虽然之前也试过改变
writing-mode
,让margin-top
能够取到50%
的高度,但是好像不是那么直接,看了 @liyongleihf2006d 的答案才知道原来如此
<div class="banner">
<img class="banner-item" src="https://placem.at/things?w=375&h=200">
</div>
<nav id="channel">
<a class="channel-item">
<img class="channel-icon" src="https://placem.at/things?w=80&h=80">
<p class="channel-title">推荐</p>
</a>
<a class="channel-item">
<img class="channel-icon" src="https://placem.at/things?w=80&h=80">
<p class="channel-title">零食</p>
</a>
<a class="channel-item">
<img class="channel-icon" src="https://placem.at/things?w=80&h=80">
<p class="channel-title">狗粮</p>
</a>
</nav>
<div class="activity">
<img class="activity-item" src="https://placem.at/things?w=200&h=120">
<img class="activity-item" src="https://placem.at/things?w=200&h=120">
<img class="activity-item" src="https://placem.at/things?w=200&h=120">
<img class="activity-item" src="https://placem.at/things?w=200&h=120">
</div>
<div id="plus">+1</div>
html,
body {
padding: 0;
margin: 0;
}
body {
max-width: 375px;
}
.banner {
font-size: 0;
}
.banner-item {
width: 100%;
}
#channel {
position: relative;
display: flex;
flex-flow: row wrap;
justify-content: space-between;
width: fit-content;
max-width: 355px;
margin: 0 auto;
background-color: #f9f9f9;
border-radius: 10px;
border: 1px solid #ccc;
}
.channel-item {
width: 40px;
height: 60px;
margin: 10px;
}
.channel-icon {
display: block;
width: 40px;
height: 40px;
}
.channel-title {
margin: 0;
font-size: 14px;
line-height: 20px;
text-align: center;
}
.activity {
box-sizing: border-box;
display: flex;
flex-flow: row wrap;
}
.activity-item {
width: 44%;
margin: 10px 3%;
border-radius: 8px;
}
#plus {
position: absolute;
top: 20px;
left: 20px;
width: 40px;
height: 40px;
line-height: 40px;
text-align: center;
color: #333;
background: lightcoral;
box-shadow: 0 0 5px 0 lightgreen;
}
let channel = document.getElementById('channel')
let plus = document.getElementById('plus')
function moveChannel () {
channel.style.marginTop = `-${channel.clientHeight / 2}px`
}
moveChannel()
function addItem () {
channel.appendChild(channel.querySelector('a.channel-item').cloneNode(true))
moveChannel()
}
plus.addEventListener('click', addItem)
Demo 当高度变化时,使用js赋值marginTop 为自身高度的一半
resizeMargin();
function resizeMargin() {
nav.style.marginTop = -0.5 * nav.clientHeight + 'px';
}
const observer = new MutationObserver(function() {
resizeMargin();
});
observer.observe(nav, {
childList: true, // 子节点的变动(新增、删除或者更改)
attributes: true, // 属性的变动
characterData: true, // 节点内容或节点文本的变动
subtree: true // 是否将观察器应用于该节点的所有后代节点
});
@liyongleihf2006 可以可以,溜溜溜。我本以为这题CSS是无解的,冒昧问下现在在哪里高就?
本期要点:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<!-- nav里面的导航的个数不固定,可能1行,也可能2行,宽度也是弹性变化的,
请实现nav元素无论里面内容如何变化,都往上偏移1/2自身的高度(注:后面的布局也跟着往上移动) -->
<title>DOM43</title>
<style>
h2 {
margin: 0;
background-color: lightblue;
height: 300px;
}
#nav {
text-align: center;
}
.container {
display: inline-block;
}
.item-container {
margin: 0;
padding: 0;
list-style: none;
display: flex;
justify-content: space-around;
align-content: space-around;
box-shadow: 0 0 0 10px lightseagreen, 0 0 0 11px black;
border-radius: 20px;
flex-flow: wrap;
}
.item {
margin: 10px;
}
footer{
margin: 0;
background-color: lightblue;
height: 300px;
}
</style>
</head>
<body>
<h2>上面的Banner</h2>
<nav id="nav" class="nav">
<div class="container">
<ul class="item-container" >
<li class="item" >
<img src="https://via.placeholder.com/150" alt="">
</li>
<li class="item" >
<img src="https://via.placeholder.com/150" alt="">
</li>
<li class="item" >
<img src="https://via.placeholder.com/150" alt="">
</li>
<li class="item" >
<img src="https://via.placeholder.com/150" alt="">
</li>
<li class="item" >
<img src="https://via.placeholder.com/150" alt="">
</li>
<li class="item" >
<img src="https://via.placeholder.com/150" alt="" id="lastImg">
</li>
</ul>
</div>
</nav>
<footer>
下面的布局
</footer>
</body>
<script>
function resize() {
nav.style.marginTop = -0.5 * nav.clientHeight + 'px'
}
resize()
const observer = new MutationObserver(function() {
resize()
})
observer.observe(nav, {
childList:true,
attibutes: true,
charactorData: true,
subtree: true,
})
window.addEventListener('resize', resize)
lastImg.addEventListener('load', resize)
</script>
</html>
@ziven27
margin
当单位是%
的时候是相对于包含快的宽度来进行计算的,也就是说.nav-in{ margin-top: -50%; /* 不理解为啥后面元素不跟随 */ }
里面的
margin-top
实际是按照.nav
的宽度来进行计算的。又因为
.nav
使用了writing-mode: vertical-lr;
属性,所以实际值是按照.nav
的高度来进行计算的。而.nav
的高度是被.nav-in
撑开的,所以.nav
是有一个高度值的,这个值就是.nav-in
的高度。最终即使
.nav-in
因为margin-top
上移了,之后的其他文案也没有跟随,因为.nav
已经有了一个高度占位了。拙见,不知道我理解的对不对。
基本是这个理解,所以最终要想底部元素往上跟随,故需要将跟随元素(必须是display:inline-block)和(进行了margin-top:-50%)元素在同一级,然后因为共同父元素 writing-mode: vertical-lr,利用 文本元素从上到下实现元素跟随
@LuckyRabbitFeet @simplefeel
margin
当单位是%
的时候是相对于包含快的宽度来进行计算的,也就是说.nav-in{ margin-top: -50%; /* 不理解为啥后面元素不跟随 */ }
里面的
margin-top
实际是按照.nav
的宽度来进行计算的。又因为
.nav
使用了writing-mode: vertical-lr;
属性,所以实际值是按照.nav
的高度来进行计算的。而.nav
的高度是被.nav-in
撑开的,所以.nav
是有一个高度值的,这个值就是.nav-in
的高度。最终即使
.nav-in
因为margin-top
上移了,之后的其他文案也没有跟随,因为.nav
已经有了一个高度占位了。拙见,不知道我理解的对不对。
是的,我也是这样想的。
可是问题在于,这个 margin-top:-50%
换成 margin-top:-40px
(这两个值是一样的),后面的元素就可以跟随了。
@LuckyRabbitFeet @simplefeel
margin
当单位是%
的时候是相对于包含快的宽度来进行计算的,也就是说.nav-in{ margin-top: -50%; /* 不理解为啥后面元素不跟随 */ }
里面的
margin-top
实际是按照.nav
的宽度来进行计算的。 又因为.nav
使用了writing-mode: vertical-lr;
属性,所以实际值是按照.nav
的高度来进行计算的。而.nav
的高度是被.nav-in
撑开的,所以.nav
是有一个高度值的,这个值就是.nav-in
的高度。 最终即使.nav-in
因为margin-top
上移了,之后的其他文案也没有跟随,因为.nav
已经有了一个高度占位了。 拙见,不知道我理解的对不对。是的,我也是这样想的。
可是问题在于,这个
margin-top:-50%
换成margin-top:-40px
(这两个值是一样的),后面的元素就可以跟随了。
@ziven27
当你使用margin-top:-40px
时,nav
的高度就是子元素高度了,子元素高度为.nav-in
本身的高度减去40px
。
/* (仅包含关键代码)*/
.nav {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(90px, 1fr));
gap: 10px;
}
.nav-item-img > img { display: block; width: 100%; max-width: 120px; margin: auto; }
```html
<header class="header-banner"></header>
<nav id="nav" class="nav">
<a href="#" class="nav-item">
<div class="nav-item-img">
<img src="https://static.easyicon.net/preview/123/1234470.gif" alt="甜甜圈">
</div>
<div class="nav-item-text">甜甜圈</div>
</a>
<!-- 略... -->
</nav>
<div>其他内容其他内容其他内容其他内容其他内容其他内容其他内容其他内容</div>
const navEl = document.getElementById('nav');
// 图像载入后再取容器高度,避免高度获取不准确。缺点是首次载入会抖动
window.addEventListener('load', fixTop);
window.addEventListener('resize', fixTop);
function fixTop() {
navEl.style.marginTop = -navEl.offsetHeight / 2 + 'px';
}
要想让元素偏移后,其他临近元素自动补上空出的位置,貌似只有 margin 有这个特性,但默认情况下 margin 的垂直方向百分比属性值是以元素宽度为基准的,这就无法利用自身高度来进行百分比偏移了。好在有
writing-mode
(张老师博客传送门)属性,结合 @liyongleihf2006 的精彩示例,我也实现了一版。
/* (仅包含关键代码)*/
.container {
width: 100%;
writing-mode: vertical-lr;
}
.container > * {
width: 100%;
writing-mode: horizontal-tb;
}
.nav {
float: left;
width: calc(100% - 15px * 2);
margin: -50% 15px 0;
}
<!-- 为了消除 writing-mode 的影响,html 结构多套了两层 -->
<header class="header-banner"></header>
<main class="container">
<nav id="nav" class="nav">
<div class="nav-inner">
<a href="#" class="nav-item">
<div class="nav-item-img">
<img src="https://static.easyicon.net/preview/123/1234470.gif" alt="甜甜圈">
</div>
<div class="nav-item-text">甜甜圈</div>
</a>
<!-- 略... -->
</div>
</nav>
<div>其他内容其他内容其他内容其他内容其他内容其他内容其他内容其他内容</div>
</main>
本期题目也是源自实际项目,关于尺寸与定位:
原图地址
大家提交回答的时候,注意缩进距离,起始位置从左边缘开始;另外,github自带代码高亮,所以请使用下面示意的格式。
其他 本期小测没有直播,也没有打分,但是会反馈要点。