Reputation: 38
I have a header on my website, which uses display: flex
. Inside it, there are three elements, a heading, an image (nested inside a div so that I can make use of a certain type of CSS image filtering) and a vertical nav.
The heading and nav have flex: 0, whereas the image has flex: 1, so it gets bigger as my display gets wider, as intended.
The nav items have a ::before pseudo element that appears on hover. When it appears, it takes up space and so my image shrinks varying amounts when I hover over the nav items and it makes my page look glitchy. How can I make it so that the ::before pseudo element does not make the image shrink when it appears? Is this even possible? Or do I need to switch to using an actual element that gets made visible when I hover?
I have tried using absolute positioning on the ::before element but then when I try to move it using the left property, it disappears.
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>
Upvotes: 1
Views: 2333
Reputation: 2011
You can update your pseudo element, like this:
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;
}
Run code snippet and open it on fullpage to see changes. 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>
Upvotes: 4
Reputation: 1541
The core issue here is:
One of those has to go.
I'm assuming you want to keep the first and remove the second.
You can't make a ::before-element take up space when the style that creates it is not enganged, so the remaining (simple) strategies I can think of are:
#1 lets you continue to base it on ::before, but is a bit brittle since it involves guesswork/knowledge of font witdth etc.
#2 is very robust, and can still be done in pure css.
#3 is in between: you still need to get the width right, but if you miss it only affects the look of the marker, not the rest of the layout
Upvotes: 1
Reputation: 294
add a max-width: (suggesting 65rem) to profile-photo3 to stop the photo shrinking the max width will never get larger than the appointed size though.
Upvotes: 0
Reputation: 38
Seeing as the nav items are unlikely to change, or if they change they will change to set values, it is fine to set the min-width of the nav to leave enough space for the ::before pseudo element, e.g. min-width: 12em
.
Upvotes: 0