如何防止 ::before 伪元素影响我的 flex 布局?

How can I prevent the ::before pseudo element from affecting my flex layout?

我的网站上有一个 header,它使用 display: flex。在它里面,有三个元素,一个标题,一个图像(嵌套在 div 中,这样我就可以使用某种类型的 CSS 图像过滤)和一个垂直导航。

标题和导航有 flex: 0,而图像有 flex: 1,所以它会随着我的显示变宽而变大,如预期的那样。

导航项有一个在悬停时出现的 ::before 伪元素。当它出现时,它会占用 space,因此当我将鼠标悬停在导航项上时,我的图像会缩小不同的量,这让我的页面看起来很乱。我怎样才能使 ::before 伪元素在出现时不会使图像缩小?这可能吗?或者我是否需要切换到使用悬停时可见的实际元素?

我曾尝试在 ::before 元素上使用绝对定位,但是当我尝试使用左侧 属性 移动它时,它消失了。

https://codepen.io/pen/?template=BamyEYW

header {
  margin-block-start: 3em;
  padding-bottom: 0.67rem;
  padding-left: 5%;
  padding-right: 5%;
  display: flex;
  flex-direction: row;
  flex-wrap: wrap;
}

nav {
  margin-left: auto;
}

nav ul {
  list-style: none;
  display: flex;
  flex-direction: column;
  padding-inline-start: 0;
  padding-left: 1em;
}

nav ul li {
  text-align: right;
  font-size: x-large;
}

nav ul li a:hover {
  color: red;
}

nav ul li.internal-nav.selected::before {
  content: '> ';
  color: rgba(0, 0, 0, 0.6);
}

nav ul li.internal-nav:hover::before {
  content: '> ';
  color: red;
}

h1 {
  color: rgba(0, 0, 0, 0.6);
  font-size: 5em;
}

.profile-photo3 {
  position: relative;
  flex: 1;
  min-width: 20rem;
  background-color: blue;
  clip-path: polygon(70% 0%, 100% 50%, 70% 100%, 0% 70%, 20% 15%);
}

.profile-photo3 img {
  width: 100%;
  mix-blend-mode: screen;
}
<header>
  <h1>Page Title</h1>
  <div class="profile-photo3"><img src="MyPhoto.jpeg" /></div>
  <nav>
    <ul>
      <li class="internal-nav"><a href="#about-me">About Me</a></li>
      <li class="internal-nav"><a href="#experience">Experience</a></li>
      <li class="internal-nav"><a href="#lab">Lab</a></li>
    </ul>
  </nav>
</header>

鉴于导航项目不太可能改变,或者如果它们改变它们将改变设置值,设置导航的 min-width 留出足够的 space 是可以的::before 伪元素,例如min-width: 12em.

添加一个 max-width:(建议 65rem)到 profile-photo3 以阻止照片缩小,但最大宽度永远不会大于指定尺寸。

您可以像这样更新您的伪元素:

nav ul li.internal-nav.selected a:before,
nav ul li.internal-nav a:hover:before {
  content: '> ';
  position: absolute;
  left: -1rem;
  color: red;
}

nav ul li.internal-nav.selected a:before {
  opacity: .6;
}

运行 代码片段并在整个页面上打开它以查看更改。 Also you can check it here (Codepen.io)

header {
  margin-block-start: 3em;
  padding-bottom: 0.67rem;
  padding-left: 5%;
  padding-right: 5%;
  display: flex;
  flex-direction: row;
  flex-wrap: wrap;
}

nav {
  margin-left: auto;
}

nav ul {
  list-style: none;
  display: flex;
  flex-direction: column;
  padding-inline-start: 0;
  padding-left: 1em;
}

nav ul li {
  text-align: right;
  font-size: x-large;
}

nav ul li a:hover {
  color: red;
}

nav ul li.internal-nav a {
  position: relative;
}

nav ul li.internal-nav.selected a:before,
nav ul li.internal-nav a:hover:before {
  content: '> ';
  position: absolute;
  left: -1rem;
  color: red;
}

nav ul li.internal-nav.selected a:before {
  opacity: .6;
}

h1 {
  color: rgba(0, 0, 0, 0.6);
  font-size: 5em;
}

.profile-photo3 {
  position: relative;
  flex: 1;
  min-width: 20rem;
  background-color: blue;
  clip-path: polygon(70% 0%, 100% 50%, 70% 100%, 0% 70%, 20% 15%);
}

.profile-photo3 img {
  width: 100%;
  mix-blend-mode: screen;
}
<head>
  <script src="https://cpwebassets.codepen.io/assets/editor/iframe/iframeConsoleRunner-d0f3648046d2aaca07bd0037b9e061a26c74a8a999b75672ad6a638cca641472.js"></script>
  <script src="https://cpwebassets.codepen.io/assets/editor/iframe/iframeRefreshCSS-4793b73c6332f7f14a9b6bba5d5e62748e9d1bd0b5c52d7af6376f3d1c625d7e.js"></script>
  <script src="https://cpwebassets.codepen.io/assets/editor/iframe/iframeRuntimeErrors-4f205f2c14e769b448bcf477de2938c681660d5038bc464e3700256713ebe261.js"></script>
</head>

<body>
  <header>
    <h1>Dogs :)</h1>
    
    <div class="profile-photo3"><img src="https://images.dog.ceo/breeds/collie-border/n02106166_2345.jpg"></div>
    
    <nav>
      <ul>
        <li class="internal-nav"><a href="#">About Dogs</a></li>
        <li class="internal-nav selected"><a href="#">My Fav Dogs</a></li>
        <li class="internal-nav"><a href="#">Dog Facts</a></li>
      </ul>
    </nav>
  </header>

  <script src="https://cpwebassets.codepen.io/assets/common/stopExecutionOnTimeout-1b93190375e9ccc259df3a57c1abc0e64599724ae30d7ea4c6877eb615f89387.js"></script>
  <script src="https://cdpn.io/cp/internal/boomboom/pen.js?key=pen.js-f2136278-4370-4b42-10b9-cde5fe228f8b" crossorigin=""></script>
</body>

这里的核心问题是:

  • 图像的大小取决于导航的宽度
  • 导航宽度发生变化

其中一个必须离开。
我假设您想保留第一个并删除第二个。

你不能让 ::before-element 占用 space 当创建它的样式没有被吸引时,所以我能想到的剩余(简单)策略是:

  1. 始终为标记保留 space(如您在回答中所建议的那样)
  2. 让标记一直占据 space(正如您在问题中建议的那样)
  3. 使标记始终不占用 space(如@yaroslav-trach 建议)

#1 让你继续基于 ::before,但有点脆弱,因为它涉及 guesswork/knowledge 字体宽度等
#2 非常健壮,仍然可以在纯 css.
中完成 #3 介于两者之间:您仍然需要获得正确的宽度,但如果您错过了它只会影响标记的外观,而不影响布局的其余部分