How to make :before & :after pseudo-elements fill remaining width? - css

So I'm trying to edit this existing widget on a page. I don't have access to edit the source code, so want to be able to do it entirely in CSS, ideally. Rather than trying to explain, I think it's easier just to paste an image of the desired behaviour - i.e. there is a left section (:before) and right section (:after) - as the splitter moves, then the widths of each pseudo element should change accordingly.
desired result
Here is a JSFiddle of a bare-bones version of the widget's code/structure
https://jsfiddle.net/o0zgyut3/
HTML
<div id='wrapper'>
<div id='splitter' style='left: 50%'></div>
</div>
<input id='slider' type='range' min='0' max='100' value='50'/>
CSS
body, html{
height: 100%;
width: 100%;
display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
background: #222;
}
input{
margin-top: 10px;
}
#wrapper{
width: 500px;
height: 50px;
background: #444;
position: relative;
display: flex;
}
/*left*/
#wrapper::before{
content:'';
width: 50px;
height: 50px;
background: linear-gradient(0deg,#00be1abf,#5fed00b3);
position: absolute;
left: 0px;
}
/*right*/
#wrapper::after{
content:'';
width: 50px;
height: 50px;
background: linear-gradient(0deg,#9f0000ff,#f10000ff);
position: absolute;
right: 0px;
}
#splitter{
position: relative;
transform: translateX(-50%);
background: #ddd;
height: 50px;
width: 10px;
z-index: 99;
}
JS (note that I wouldn't have access to the JS in the real site - the slider in this example below is just to allow changing the splitter position easily while debugging (without having to add the drag functionality)
document.getElementById("slider").addEventListener("change", function(){
document.getElementById("splitter").style.left = this.value + "%";
})
I have tried various approaches (with flex, inline, grid, floats, margins etc) and could get behaviour that was half-way to what I wanted, but never exactly. Also note, that, if it's easier, the real widths don't have to be accurate - it's a purely visual widget, so it's fine to e.g. make the right section 100% width, then only the left section is dynamic and position it above the right by giving it a higher z-index, if that's easier - i.e. if the right section was hard-coded at 100% width, and the left derived an 80% width from the css, it would give the illusion of an 80:20 split (even though it'd technically be 80:100), which is fine
Anyway, I suspect I'm missing something fairly obvious, so if anyone is able to get this working, that'd be awesome. Thanks

It's not possible that you directly access pseudo-elements with JS as when the page loads they're not part of the DOM.
However, you can do something like this create a new style element which will have new CSS for your wrapper
Run snippet below to see it working.
document.getElementById("slider").addEventListener("change", function() {
document.getElementById("splitter").style.left = this.value + "%";
var sytleElement = document.head.appendChild(document.createElement("style"));
sytleElement.innerHTML = "#wrapper:before {width: " + this.value + '%' + " }";
})
body,
html {
height: 100%;
width: 100%;
display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
background: #222;
}
input {
margin-top: 10px;
}
#wrapper {
width: 500px;
height: 50px;
background: #444;
position: relative;
display: flex;
}
/*left*/
#wrapper::before {
content: '';
width: 10%;
height: 50px;
background: linear-gradient(0deg, #00be1abf, #5fed00b3);
position: absolute;
left: 0px;
}
/*right*/
#wrapper::after {
content: '';
width: 50px;
height: 50px;
background: linear-gradient(0deg, #9f0000ff, #f10000ff);
position: absolute;
right: 0px;
}
#splitter {
position: relative;
transform: translateX(-50%);
background: #ddd;
height: 50px;
width: 10px;
z-index: 99;
}
<div id='wrapper'>
<div id='splitter' style='left: 10%'></div>
</div>
<input id='slider' type='range' min='0' max='100' value='10' />

Related

Extending a line to the left of an element without overlapping the element

I am trying to create a solid line that extends both to and from the left side of an element. I can create one that extends to the left, but it overlaps the element (in this case an H2). I need it to "start" before the text does. I can use something like right: 15px to solve this problem, but I would need to adjust the px size in every instance this is used since some H2s will be longer, and some shorter. I would like to find a solution that doesn't require different right values since this will be used with multiple H2s of various lengths.
Here is the code I am using now:
h2::before {
display: inline-block;
content: "";
height: 3px;
background: #E47325;
position: absolute;
width: 400%;
top: 50%;
margin-top: -2px;
}
This is how it currently looks:
And this is how I would like it to look ideally, without having to arbitrarily set padding to the right side:
Something like this?
body {
text-align: center;
}
h2 {
position: relative;
display: inline-block;
}
h2::before {
display: inline-block;
content: "";
height: 3px;
background: #E47325;
position: absolute;
width: 100%; /* Added */
top: 50%;
left: calc(-100% - 10px); /* Added */
margin-top: -2px;
}
/* And the same on the other side */
h2::after {
display: inline-block;
content: "";
height: 3px;
background: #E47325;
position: absolute;
width: 100%;
top: 50%;
left: calc(100% + 10px); /* Different here */
margin-top: -2px;
}
<h2>Hello</h2>
Wrap <h2> in a <header> (or any block element but <header> is 100% semantic).
Assign ::before to <header> instead. Make <header> position: relative
Assign h2 position: absolute and z-index: 1
Assign header::before position: absolute as well
The height and top values are based on the browser default font-size: 1.5em of h2 -- so adjust accordingly if h2 font-size has been altered.
header {
position: relative;
height: 1.625em;
}
h2 {
position: absolute;
z-index: 1;
right: 0;
top: calc(50% - 1.3125em);
width: max-content;
background: #FFFFFF;
}
header::before {
content: " ";
display: block;
position: absolute;
top: calc(50% - 1.5px);
height: 3px;
width: 99%;
background: #E47325;
}
<header>
<h2>HEADING</h2>
</header>
<header>
<h2>A LONGER HEADING</h2>
</header>

CSS responsive div prevent cutting off with overflow hidden

I am using this layout for responsive div that maintains aspect ratio. It works well, but it requires overflow: hidden, to be clear it's padding-top: 56.25% defined in :after. If there is no overflow on wrapper, next element (in this case href link) is blocked.
My question is: is there a way to achieve same result without overflow: hidden on wrapper? I need some element to be visible outside wrapper without being cutting off.
Open snippet in full page if you can't see the issue within a small window.
#wrapper {
position: relative;
max-width: 1000px;
min-width: 350px;
max-height: 383px;
border: 1px solid;
/*overflow:hidden;*/
}
#wrapper:after {
padding-top: 56.25%;
display: block;
content: '';
background: rgba(0,0,0,.25);
}
<div id="wrapper"></div>
click me
You can add a inner div and make it responsive with a pseudo element like you did before, and apply overflow: hidden; on it. Then add another sibling div and set the style you wish to apply, it would be div #test in the example, as you see it will be visible outside the wrapper.
#wrapper {
position: relative;
max-width: 1000px;
border: 1px solid;
}
#inner {
min-width: 350px;
max-height: 383px;
overflow: hidden;
}
#inner:after {
background: rgba(0,0,0,.25);
padding-top: 56.25%;
display: block;
content: '';
}
#test {
position: absolute;
right: 0;
bottom: 0;
transform: translateY(100%);
width: 100px;
height: 50px;
background: aqua;
}
<div id="wrapper">
<div id="inner"></div>
<div id="test"></div>
</div>
click me

Fixed side bar is not scrolling with page contents

I've a fixed side bar on the right side of the page (position: fixed)
But it's contents are not fully visible as it's not scrolling with the page scroll. I could have added overflow-y: scroll in the .sidebar{} css settings. But don't want a separate scroll bar for sidebar. Is there an option to make it scroll with the full page scroll.
Here is my css settings for sidebar :
.sidebar {
text-align: center;
padding: 2rem,1rem;
color: rgba(255,255,255,.5);
background-color: #202020;
top: 0;
bottom: 0;
}
If you want to debug to see what went wrong, here is it running live : https://pagefault.me
Thanks
Based on the answer I suggested in my comment, I was able to work in chrome to arrive at the css below.
1) Add some css to the .sidebar-nav component
nav.sidebar-nav {
position: absolute;
overflow-y: scroll;
top: 100px; /*100px to give some room for the sidebar heading (without this, absolute position will make the nav overlap)*/
left: 15px; /* you can make this zero and add `padding-left: 15px` */
bottom: 15px; /* leave some room for copyright section */
right: -17px; /*this may vary from browser to browser (i suggest using the width of the widest scrollbar, then adjust for padding-right)*/
padding-right: 15px; /*padding to prevent the text from flowing off screen*/
}
2) The .container class becomes
.sidebar .container{
max-width: 38rem;
padding-left: 1rem;
padding-right: 1rem;
margin-left: auto;
margin-right: auto;
height: 100%;
position: relative;
overflow: hidden;
}
3) Make sure the footer bit remains at the bottom after making .sidebar-nav absolute
.sidebar .container > p:last-of-type {
position: absolute;
bottom: -15px;
}
Of course as mentioned in the original solution, you have to test the scrollbar widths in different browsers to arrive at the right width to use in place of right: -17px in step 1.
Use absolute position instead of fixed as you want it to scroll it along with the page.
body {
margin: 0;
padding: 0;
position: relative;
}
main {
position: absolute;
top: 0;
left: 0;
width: 80%;
height: 300vh;
background: beige;
}
aside {
position: absolute;
top: 0;
right: 0;
width: 20%;
height: 300vh;
background: black;
color: white;
}
<main></main>
<aside><aside>
A flex box solution without positioning :
body {
margin: 0;
padding: 0;
display: flex;
}
main {
width: 80%;
height: 300vh;
background: beige;
}
aside {
width: 20%;
height: 300vh;
background: black;
color: white;
}
<main></main>
<aside></aside>

Why defining body attributes in css?

I have seen some web design lessons that always start with a css like this:
body,html {
display: block;
width: 100%;
height: 100%;
padding: 0;
margin: 0;
}
I'm trying to figure out what's the point of declaring attributes like width, height or display for body and html that are, if I'm not wrong, by default in browsers.
I thought it would be to prevent and undefined return or similar when accessing the css with js, but the result is the same when the attributes are defined in the css than when left to default:
console.log($("BODY").css('width')); // Always returns the width of the body
I also thought it could be to start the inheritance in cascade elements, but a div inside the body inherits the value just the same.
Anybody knows a solid reason for this approach? any browser / device issue I have missed? future compatibility? plain pedantry?
I'm kind of curious about it.
I found a good reason to define the html and body width and height to 100%. Say you want to vertically align a relative positioned div, you need to put it into an absolute positioned container:
html,
body {
margin: 0;
padding: 0;
}
#container {
position: absolute;
width: 100%;
height: 100%;
}
#main {
background: lightgrey;
position: relative;
top: 50%;
transform: translateY(-50%);
width: 100px;
height: 100px;
text-align: center;
margin-left: auto;
margin-right: auto;
}
<div id="container">
<div id="main">
<h1>MY DIV</h1>
</div>
</div>
But, setting the body width and height to 100% you get an absolute positioned container that covers the whole window:
html,
body {
margin: 0;
padding: 0;
width: 100%;
height: 100%;
}
#main {
background: lightgrey;
position: relative;
top: 50%;
transform: translateY(-50%);
width: 100px;
height: 100px;
text-align: center;
margin-left: auto;
margin-right: auto;
}
<div id="main">
<h1>MY DIV</h1>
</div>
You get the same result, but it saves you a div element.

Move absolute div outside the parent

Is it possible to move an absolute positioned div outside the parent's borders?
I tried (less) left:calc(~'0%-15px') but does not seem to work :)
.dif-links {
background: pink; width: 25px; height: 100px;
position: absolute; text-align: center;
left:calc(~'0%-15px')
}
I have an article and I would like to maintain the "share" div outisde the article body, this is why I used the absolute position, but now just move it to the left side of parent seems to be complicated...
Here is my pen
Assuming the parent is its containing block (e.g. has position: relative), the easiest way is
position: absolute;
right: 100%;
#wrapper {
position: relative;
background: yellow;
margin: 0 50px;
height: 50px;
}
#inner {
position: absolute;
right: 100%;
border: 2px solid red;
}
<div id="wrapper">
<div id="inner">Foo</div>
</div>
Just set a margin-left of -25px.
i have try like this please check,
.dif-links{
background: pink; width: 25px; height: 100px; position: absolute; text-align: center;left:-15px; top:0;}
.container {
width: #w;
height: calc(~'100% - '#h);
background: yellow;
margin: 0 auto;
border-collapse: collapse;
margin-top: #h;
position:relative;
}
The below css seems to work like you expected. I have not used calc() method but i am sure you can tweak it now to fit your need.
.dif-links {
background: pink;
width: 25px;
height: 100px;
position: absolute;
text-align: center;left:365px;
}
Hope this Helps!
Happy Styling.

Resources