How to prevent: pseudo-elements with dynamically random position when scrollbar appears?
When the scroll bar appears, the :pseudo
items inside relative
are element
no longer in the right place.
Instead, they just flow somewhere inside element
.
Let's say I have the following markup. As you can see, elements :pseudo
adhere nicely to the edges of the element.
Fragment where :pseudo
are located well if there is no scrollbar
.without-scroll-bar {
border: 5px solid green;
padding: 15px;
position: relative;
}
.without-scroll-bar:before,
.without-scroll-bar:after {
position: absolute;
content: "";
height: 20px;
width: 20px;
}
.without-scroll-bar:before {
border-top: 5px solid red;
border-right: 5px solid red;
top: -5px;right: -5px;
}
.without-scroll-bar:after {
border-right: 5px solid red;
border-bottom: 5px solid red;
bottom: -5px;right: -5px;
}
<div class="without-scroll-bar">
<p>This is just some example text.</p>
</div>
However, when I make it element
fixed max-height
, so if it reaches it, it shows the scrollbar. Items are :pseudo
no longer located. They just flow somewhere inside the container.
A snippet that is :pseudo
not marked as disabled
code {
background: #ededed;
padding: 3px;
}
.with-scroll-bar {
border: 5px solid green;
padding: 15px;
position: relative;
max-height: 300px;
overflow-y: auto;
overflow-x: hidden;
}
.with-scroll-bar:before,
.with-scroll-bar:after {
position: absolute;
content: "";
height: 20px;
width: 20px;
}
.with-scroll-bar:before {
border-top: 5px solid red;
border-right: 5px solid red;
top: -5px;right: -5px;
}
.with-scroll-bar:after {
border-right: 5px solid red;
border-bottom: 5px solid red;
bottom: -5px;right: -5px;
}
<div class="with-scroll-bar">
<p>As you can see, the <code>:pseudo</code> elements are not in position anymore</p>
<p>This is just some example text.</p>
<p>This is just some example text.</p>
<p>This is just some example text.</p>
<p>This is just some example text.</p>
<p>This is just some example text.</p>
<p>This is just some example text.</p>
<p>This is just some example text.</p>
<p>This is just some example text.</p>
<p>This is just some example text.</p>
<p>This is just some example text.</p>
<p>This is just some example text.</p>
<p>This is just some example text.</p>
<p>This is just some example text.</p>
<p>This is just some example text.</p>
<p>This is just some example text.</p>
<p>This is just some example text.</p>
<p>This is just some example text.</p>
<p>This is just some example text.</p>
<p>This is just some example text.</p>
<p>This is just some example text.</p>
<p>This is just some example text.</p>
<p>This is just some example text.</p>
<p>This is just some example text.</p>
</div>
- How can I prevent this?
- How can I make the layout I want also apply on
elements
with scrollbars? - Better yet, how can I make the elements
:pseudo
stay on the edges? Like the first snippet, but then also with a scrollbar on the container?
Oh, I must point out that I have no access to myself HTML
. So I can't just wrap around it div
and then add items :pseudo
to div
.
source to share
JavaScript
If you can use JavaScript, another way would be to use the wrap () function from jQuery and add the pseudo-elements later to that wrapper div. Therefore, you still don't need to change anything in your HTML structure as JavaScript will do it for you.
Js
$(".with-scroll-bar").wrap("<div id='wrapper' />");
$(".with-scroll-bar").wrap("<div id='wrapper' />");
body {
height: 1000px;
}
code {
background: #ededed;
padding: 3px;
}
#wrapper {
position: relative;
}
.with-scroll-bar {
border: 5px solid green;
padding: 15px;
position: relative;
max-height: 300px;
overflow-y: auto;
overflow-x: hidden;
}
#wrapper:before,
#wrapper:after {
position: absolute;
content: "";
height: 20px;
width: 20px;
z-index: 1000;
}
#wrapper:before {
top: 0;
right: 0;
border-top: 5px solid red;
border-right: 5px solid red;
}
#wrapper:after {
bottom: 0;
right: 0;
border-right: 5px solid red;
border-bottom: 5px solid red;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<p>This is just some example text.</p>
<p>This is just some example text.</p>
<div class="with-scroll-bar">
<p>As you can see, the <code>:pseudo</code> elements are not in position anymore</p>
<p>This is just some example text.</p>
<p>This is just some example text.</p>
<p>This is just some example text.</p>
<p>This is just some example text.</p>
<p>This is just some example text.</p>
<p>This is just some example text.</p>
<p>This is just some example text.</p>
<p>This is just some example text.</p>
<p>This is just some example text.</p>
<p>This is just some example text.</p>
<p>This is just some example text.</p>
<p>This is just some example text.</p>
<p>This is just some example text.</p>
<p>This is just some example text.</p>
<p>This is just some example text.</p>
<p>This is just some example text.</p>
<p>This is just some example text.</p>
<p>This is just some example text.</p>
<p>This is just some example text.</p>
<p>This is just some example text.</p>
<p>This is just some example text.</p>
<p>This is just some example text.</p>
<p>This is just some example text.</p>
</div>
CSS
There is also another pure CSS solution, but this is very hacky. This only works in Chrome as far as I could see and it doesn't support dynamic div height. This means that if the scrollbar is missing, the layout will break.
body {
height: 1000px;
transform: translateZ(0);
}
code {
background: #ededed;
padding: 3px;
}
.with-scroll-bar {
border: 5px solid green;
padding: 15px;
position: relative;
max-height: 300px;
overflow-y: auto;
overflow-x: hidden;
display: flex;
flex-direction: column;
}
.with-scroll-bar:before,
.with-scroll-bar:after {
position: fixed;
display: flex;
align-self: flex-end;
content: "";
height: 20px;
width: 20px;
}
.with-scroll-bar:before {
border-top: 5px solid red;
border-right: 5px solid red;
margin-top: -20px;
margin-left: 34px;
}
.with-scroll-bar:after {
border-right: 5px solid red;
border-bottom: 5px solid red;
margin-top: 295px;
margin-left: 34px;
}
<p>This is just some example text.</p>
<p>This is just some example text.</p>
<div class="with-scroll-bar">
<p>As you can see, the <code>:pseudo</code> elements are not in position anymore</p>
<p>This is just some example text.</p>
<p>This is just some example text.</p>
<p>This is just some example text.</p>
<p>This is just some example text.</p>
<p>This is just some example text.</p>
<p>This is just some example text.</p>
<p>This is just some example text.</p>
<p>This is just some example text.</p>
<p>This is just some example text.</p>
<p>This is just some example text.</p>
<p>This is just some example text.</p>
<p>This is just some example text.</p>
<p>This is just some example text.</p>
<p>This is just some example text.</p>
<p>This is just some example text.</p>
<p>This is just some example text.</p>
<p>This is just some example text.</p>
<p>This is just some example text.</p>
<p>This is just some example text.</p>
<p>This is just some example text.</p>
<p>This is just some example text.</p>
<p>This is just some example text.</p>
<p>This is just some example text.</p>
</div>
source to share
The idea is that you need to skip using pseudo altogether. What you can do is add two elements, using Javascript
one at the beginning of the other at the end.
Since they are :Pseudo elements
never DOM bound, you need these elements to manipulate the positions of your newly added elements according to your requirements
there are some edge cases in the above example and these two buttons are only for changing the height of your parent div. You will get the basic idea and have to correct them accordingly.
source to share
As you can easily see, by making the pseudo-elements more visible (for example, on all four sides), they are laid out in the same way as when the maximum height is not reached: in the corners of the space that the element occupies, not at the top and bottom of its content.
Predictable layouts include position: fixed or, as in the following, placing pseudo-elements on a line. What are you using pseudo-elements for?
code {
background: #ededed;
padding: 3px;
}
.with-scroll-bar p{
margin:15px;
}
.with-scroll-bar {
border: 5px solid green;
padding: 0px;
position: relative;
max-height: 300px;
overflow-y: auto;
}
.with-scroll-bar:before,
.with-scroll-bar:after {
border: 5px solid red;
display:block;
content: "";
height: 20px;
}
.with-scroll-bar:before
{
left:0px;
width:20px;
margin:0px;
}
.with-scroll-bar:after {
left:0px;
right:0px;
margin:0px;
}
<div class="with-scroll-bar">
<p>As you can see, the <code>:pseudo</code> elements are not in position anymore</p>
<p>This is just some example text.</p>
<p>This is just some example text.</p>
<p>This is just some example text.</p>
<p>This is just some example text.</p>
<p>This is just some example text.</p>
<p>This is just some example text.</p>
<p>This is just some example text.</p>
<p>This is just some example text.</p>
<p>This is just some example text.</p>
<p>This is just some example text.</p>
<p>This is just some example text.</p>
<p>This is just some example text.</p>
<p>This is just some example text.</p>
<p>This is just some example text.</p>
<p>This is just some example text.</p>
<p>This is just some example text.</p>
<p>This is just some example text.</p>
<p>This is just some example text.</p>
<p>This is just some example text.</p>
<p>This is just some example text.</p>
<p>This is just some example text.</p>
<p>This is just some example text.</p>
<p>This is just some example text.</p>
</div>
source to share