CSS定位与布局问题:绝对定位问题?

css问题 下面代码 为什么ul使用绝对定位居中 a元素变成块元素 文字会垂直
代码

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<style>
    *{
        /* 初始化 取消页面的内外边距 */
        margin: 0;
        padding: 0;
    }
    body{
        /* 100%窗口高度 */
        height: 100vh;
        /* 渐变背景 本人比较偏爱渐变背景 */
        background: linear-gradient(200deg,#dad4ec,#f3e7e9);
    }
    ul{
        /* 绝对定位 水平、垂直居中 */
        position: absolute;
        top: 50%;
        left: 50%;
        transform: translate(-50%,-50%);
        /* 弹性布局 */
        display: flex;
        margin: 0;
        padding: 0;
    }
    ul li{
        list-style: none;
        /* 这里加个动画过渡 */
        transition: 0.5s;
    }
    ul li a{
        /* 相对定位 */
        position: relative;
        display: block;
        text-align: center;
        margin: 0 30px;
        color: #333;
        font-size: 40px;
        text-decoration: none;
    }
</style>
<body>
<ul>
    <li><a href="#">首页</a></li>
    <li><a href="#">关于我们</a></li>
    <li><a href="#">服务</a></li>
    <li><a href="#">案例</a></li>
    <li><a href="#">用户反馈</a></li>
</ul>
</body>
</html>

为什么用绝对定位居中宽度展示文字会被挤下去
如下图

如果用flex布局居中就是没问题
代码如下图

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <style>
        *{
            /* 初始化 取消页面的内外边距 */
            margin: 0;
            padding: 0;
        }
        body{
            display: flex;
            justify-content: center;
            align-items: center;
            /* 100%窗口高度 */
            height: 100vh;
            /* 渐变背景 本人比较偏爱渐变背景 */
            background: linear-gradient(200deg,#dad4ec,#f3e7e9);
        }
        ul{
            /* 绝对定位 水平、垂直居中 */

            /* 弹性布局 */
            display: flex;
            margin: 0;
            padding: 0;
        }
        ul li{
            list-style: none;
            /* 这里加个动画过渡 */
            transition: 0.5s;
        }
        ul li a{
            /* 相对定位 */
            position: relative;
            display: block;
            text-align: center;
            margin: 0 30px;
            color: #333;
            font-size: 40px;
            text-decoration: none;
        }
    </style>
    <body>
    <ul>
        <li><a href="#">首页</a></li>
        <li><a href="#">关于我们</a></li>
        <li><a href="#">服务</a></li>
        <li><a href="#">案例</a></li>
        <li><a href="#">用户反馈</a></li>
    </ul>
    </body>
    </html>

效果如下图

阅读 1.9k
avatarAI BotBETA

在CSS中,绝对定位(position: absolute;)会脱离元素在文档流中的正常位置,并将其放置在相对于最近的已定位祖先元素(而非正常流)的位置。如果没有已定位的祖先元素,那么它会相对于初始包含块进行定位。绝对定位元素的位置通过 toprightbottomleft 属性来设定。

在你提供的CSS代码中,ul 元素被设定为绝对定位,并通过 top: 50%;left: 50%; 将其置于容器的中心。然后通过 transform: translate(-50%,-50%); 将其自身中心点移动到容器的中心点,实现了水平和垂直居中。

至于为什么使用绝对定位后 a 元素会变成块元素并文字垂直居中,这主要归功于以下两点:

  1. 块元素显示: ul li a 选择器中的 display: block; 使得 a 元素以块级元素的方式显示。块级元素通常会独占一行,并且可以设置宽度、高度、内外边距等属性。
  2. 垂直对齐: ul 元素使用 display: flex; 设定了弹性布局,但由于 a 元素是相对定位(position: relative;),它不会受到 ul 元素弹性布局的对齐影响。然而,a 元素本身的文本内容因为 display: block;text-align: center; 的设置而实现了水平居中。对于垂直居中,由于 a 元素是块级元素,并且没有设置具体的高度,文本内容会默认垂直居中。

如果 body 使用 display: flex; 并尝试居中 ul,那么 ul 会作为 body 的直接子元素在弹性容器中居中,而不是相对于整个窗口。这可能会影响布局,因为 flex 布局与 absolute 定位在定位机制上是不同的。使用 absolute 定位允许 ul 脱离文档流,并通过 transform 属性进行精确的定位和居中,而 flex 布局则会根据容器中项目的属性和弹性容器的属性来分配空间和对齐内容。

5 个回答

其实和absolute元素的block width的计算有关

css2 block width: Absolutely positioned, non-replaced elements

the constraint that determines the used values for these elements is:
left + margin-left + border-left-width + padding-left + width
+ padding-right + border-right-width + margin-right + right = width of containing block(解读: static定位时,是不需要考虑left和right的。我们对最终效果的不理解大概是没有考虑到left和right)

该问题背景下应该应用以下计算规则。

Otherwise, set 'auto' values for 'margin-left' and 'margin-right'
to 0, and pick the one of the following six rules that applies.

  1. width and right are auto and left is not auto, then the width is shrink-to-fit . Then solve for right

如何计算shrink-to-fit?

Calculation of the shrink-to-fit width is similar to calculating the width of a table cell using the automatic table layout algorithm. Roughly: calculate the preferred width(解读:最大内容宽度?) by formatting the content without breaking lines other than where explicit line breaks occur, and also calculate the preferred minimum width(解读:最小内容宽度?), e.g., by trying all possible line breaks. CSS 2.1 does not define the exact algorithm. Thirdly, calculate the available width: this is found by solving for 'width' after setting 'left' (in case 1) or 'right' (in case 3) to 0.(解读:这里我们需要先假设right为0)
Then the shrink-to-fit width(解读:fit-content?) is: min(max(preferred minimum width, available width), preferred width).

在该问题背景下,最终计算得到的shrink-to-fit width应该是available width

  • 如果包含块再小一些的话,就可能是preferred minimum with,每一个元素都被挤到一列排布了。
  • 如果包含块比较大的话(可以通过缩放页面来得到一个大的包含块),就可能是preferred with,每个元素的文本按一行来排布。

最后再计算right(之前在计算width的时候假设right为0,并不是它最终的计算值)。该问题背景下right应该为0。但是从最终的效果来看,它是水平居中的,离着右侧边缘还有一定的距离,怎么会是0呢?因为我们使用了transform: translate(-50%, -50%)

附:
由于对absolute元素的block width的计算产的误解而导致和预想的不一致或对产生的效果不理解的问题,看到过几次了。(今天我在为回答问题overflow创建的BFC和float创建的BFC 为什么会有这样的区别?而查阅资料的时候,偶然在文档中发现对应的说明😂。)

你说的a元素变成块元素,是因为你给a元素加了display: block;

解决:加一个不换行属性:white-space: nowrap;

image.png

为你的ul 添加两个样式

ul{
    /* 绝对定位 水平、垂直居中 */
    position: absolute;
        width:100%
    top: 50%;
    left: 50%;
    transform: translate(-50%,-50%);
    /* 弹性布局 */
    display: flex;
        justify-content: center;
    margin: 0;
    padding: 0;
}

跟绝对定位无关,是 display: flex 的问题:

ul {
  /* 绝对定位 水平、垂直居中 */
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  /* 弹性布局 */
  display: flex;
  margin: 0;
  padding: 0;

  flex-direction: column; /* 加上这一行 */
}

绝对定位之后,元素的宽度就发生了变化,默认从撑满(100%),变成了最小内容(min-content),而你的中文文字可以换行,所以元素就把内容挤换行,然后变窄。

解决方案很多,根据不同需求,可以:

  1. 不让文字换行
  2. 给每个链接添加宽度或最小宽度
  3. 给元素添加宽度
推荐问题
宣传栏