I'm looking for a relatively simple and standard way of changing CSS pseudoelement property value by JS Scrollspy.
The parent element (section of a landpage) should change grayscale, while scrolled, and its child should have position:fixed.
As it turns out, it's impossible to make it in an easy way, because any filter is removing position:fixed by definition. More about this: CSS-Filter on parent breaks child positioning
Moving that background-image to a pseudoelement creates another problem: manipulation of the pseudoelement's properties by JS.
The expected result: I wanted to make a section of a landing page, having grayscale filter for background image. That's the easy part. But it should has less grayscale, while moving upward (the more picture user see, the more color it has), and centered content element shuffles up from previous section, and later hiding under next one.
So basically I need two things:
filter grayscaled background image, with dynamically changing value of a grayscale, relative to distance to the top of the window (JS scrollspy)
position:fixed central content element visible only in that section
Illustration (with background-picture in pseudoelement) is here: https://codepen.io/tdudkowski/pen/MLyMyG
HTML
<section class="one">
</section>
<section class="two">
<div><p>DIV with a position:fixed</p></div>
</section>
<section class="three"></section>
CSS
section {
position: relative;
max-width: 1000px;
height: 70vh;
background-color: #eee;
margin: 0 auto;
overflow: hidden;
}
.two {
background-color: transparent;
/* Try to uncomment rule below */
/* filter: grayscale(50%); */
}
.two div {
position: fixed;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
width: 30rem;
height: 10rem;
background-color: #f00;
z-index: 1;
}
.one,
.three {
z-index: 100;
}
/* background of section */
section.two::after {
content: "";
position: absolute;
left: 0;
right: 0;
top: 0;
bottom: 0;
background-image: url(https://picsum.photos/1000/200);
background-size: cover;
background-repeat: no-repeat;
z-index: -1;
/* filter: grayscale(50%); */
}
Related
I've been trying to create a sticky position image that changes as it scrolls across the border between two sections of my page. So basically, there should be two sticky position images, the top one gets masked by the bottom section and the bottom gets masked by the top section. I am having trouble figuring out a way to mask both images at the same time (you can use the bottom section div to hide the top image, and vice versa, but not both at the same time).
Here's an image to illustrate what I'm trying to do
Here's the code I'm using:
.lblue {
height: 40vh;
width:10vw;
position: -webkit-sticky;
position: sticky;
top:30vh;
left:45vw;
background:lightblue;
}
.lred {
height: 40vh;
width:10vw;
position: -webkit-sticky;
position: sticky;
top:30vh;
left:45vw;
background:lightcoral;
}
.blue {
position: absolute;
top:0;
height:150vh;
width:100vw;
background:blue;
}
.red {
position: absolute;
top:100vh;
height:100vh;
width: 100vw;
background:red;
}
<div class="blue">
<div class="lblue"></div>
</div>
<div class="red">
<div class="lred"></div>
</div>
Thank you!
Here’s a solution. The trick is to use the images as CSS backgrounds, because CSS backgrounds can be easily fixed in the viewport of their parents.
.blue {
position: absolute;
top:0;
height:150vh;
width:100vw;
background: blue fixed linear-gradient(lightblue, lightblue) 45vw 30vh / 10vw 40vh no-repeat;
}
.red {
position: absolute;
top:100vh;
height:100vh;
width: 100vw;
background: red fixed linear-gradient(lightcoral, lightcoral) 45vw 30vh / 10vw 40vh no-repeat;
}
<div class="blue"></div>
<div class="red"></div>
In this solution, you can replace linear-gradient(color, color) by the URL of your image, using url(https://…). I used gradients because, for the browser, gradients are (generated) images. So, this trick actually works with images.
The position: absolute also becomes useless, at least for the demo.
The long background rule may need some explanations. background is a shorthand (= a short way to write several properties in a single line) for:
background-color: red;
background-attachement: fixed;
background-image: linear-gradient(lightcoral, lightcoral);
background-position: 45vw 30vh;
background-size: 10vw 40vh;
background-repeat: no-repeat;
position:fixed can do this if you conside a clip-path trick to hide the overflow so that each element will show only inside its section
.lblue,
.lred {
height: 40vh;
width: 10vw;
position: fixed;
top: 30vh;
left: 45vw;
background: lightblue;
}
.lred {
background: lightcoral;
}
.blue,
.red {
height: 100vh;
background: blue;
clip-path: inset(0 0 0 0); /* this is important */
}
.red {
background: red;
}
body {
margin: 0
}
<div class="blue">
<div class="lblue"></div>
</div>
<div class="red">
<div class="lred"></div>
</div>
My engagement-filtercontainer div used to sit directly above my engagement-graphcontainer unless it was expanded via button click, in which case it drops down into the graphcontainer overlapping. Now the engagement-filtercontainer has grown in size because of additional content and it overlaps my graph container which contained my svg. I need it to dynamically not do this even if my filter increases in size.
I have some divs that are contained in this order:
<div class="Engagement-Container">
<div class="Engagement-Body">
<div class="Engagement-Graph" id="graph">
<div class="Engagement-FilterContainer"
</div>
<div class="Engagement-GraphContainer"
<svg
class="Engagement-GraphSVG"
xmlns="http://www.w3.org/2000/svg"
version="1.1 ">
</svg>
</div>
</div>
</div>
</div>
Notice that the engagement-filtercontainer and graphcontainer are both within the engagement-graph div, and that my svg is contained within the graphcontainer.
In the below image you can see that the filter now with more content expands into the area (I have hidden with css thats why im showing it in dev mode, ive tried various methods to work around this but I think i need a definitive solution.
The CSS:
engagement-graph(parent div)
.Engagement-Graph {
position: absolute;
width: 100%;
height: 100%;
font-size: 100%;
vertical-align: baseline;
overflow: hidden;
#include tablet() {
width: 65%;
}
}
Engagement-graph-container (contains the svg graph that i want to protect from unwanted overlap)
.Engagement-GraphContainer {
position: relative;
width: 100%;
height: calc(100% - 56px);
top: 0;
background-color: $gray-bg-color;
transition: height $filter-slide-duration, top $filter-slide-duration;
#include tablet() {
background-color: white;
height: 100%;
}
svg {
width: 100%;
height: 100%;
}
&--WithFilter {
height: calc(100% - 480px) !important;
top: 480px !important;
#include landscape {
height: calc(100% - 436px) !important;
top: 436px !important;
}
}
}
Filter-container (that is overlapping)
.Engagement-FilterContainer {
overflow: overlay;
display: table;
position: absolute;
width: 100%;
z-index: 10;
transition: transform $filter-slide-duration;
transform: translateY(-486px);
visibility: hidden;
&--Visible {
transform: translateY(0) !important;
}
#include landscape {
transform: translateY(-436px);
}
}
I wish for the filter to work as usual so when its expanded it will appear into the screen but when it is not, I don't want it encroaching upon the graph, no matter how large it gets. When the filter was smaller it was fine it never came into the screen, so it must not be dynamic in how it is sized.
Thank you if you can help.
I have the following structure:
<div id="hold">
<div id="hold-left">content</div>
<div id="hold-right">content</div>
</div>
hold-left floats to the left and hold-right floats to the right. The widths are 40% and 55% when the page is loaded. The thing is, hold-right is a sort of preview of something and the user needs to be able to resize it.
This is easily done using JavaScript (the user selects a zoom level radio button), however the issue I am now facing is that, if it is enlarged, it drops down beneath hold-left. What I'd like it to do is float over freely to the outside of the parent div.
How do I go about this? Can it be done through CSS at all, or do I need to dynamically resize the parent every time I resize hold-right?
Have you considered using a left margin on .hold-right?
.hold-left{
float:left;
width:40%;
}
.hold-right{
margin-left:45%;
}
Also, generally you should use classes, not IDs.
You can try with display: table, and table-cell.
The table will need to be 100% width and no width specified for table-cell. Then the content will "resize" the cells.
Otherwise, you will need to use javascript to update both cells.
Use position property in css. Checkout this
position: relative; in the parent.
position: absolute; in the each child.
#hold {
position: relative;
}
#hold-left {
position: absolute;
left: 0;
width: 100px;
height: 100px;
background: red;
}
#hold-right {
position: absolute;
right: 0;
width: 100px;
height: 200px;
background: yellow;
}
#zoomLevelSelector {
position: absolute;
top: 0;
left: 0;
z-index: 0;
}
I have a div that is centered on the middle of the screen. I need to pass some text to the div and the text will be of various lengths. The problem is that when I pass text to the div, it changes size but wont stay centered. Here's a JSFiddle that demonstrates the problem.
I currently center the div like this:
position: absolute;
top: 50%;
left: 50%;
Add this line:
#divError{
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%,-50%);
http://jsfiddle.net/h0d097vp/3/
Your div is not centered. The existing positioning centered the top left corner of the div.
Try this:
#divError{
position: absolute;
top: 50%;
left: 50%;
transform:translate(-50%,-50%);
}
JSfiddle Demo
Can you set constant width?, if so here's your answer JSFiddler
Just added
width: 100px;
right: 0;
left: 0;
margin: auto;
Your div is not centered in the beginning either. left: 50% means that the diff starts at 50%, which means that the start of the div is at the center of the page.
When the div has a width of 200px, than still only the start will be at the center.
You can give the div a fixed width, and than add a negative margin of half the width so the div will really be in the center of the page.
Like
#divError{
width: 200px;
margin-left: -100px;
}
When using top and left they position whichever side they are named directly at the position given. So left: 50% will always have the leftmost side positioned directly at the 50% mark. This is not the center, but starts the left side of the div at the center. The same occurs with top: 50%. In order to use top and left you'd need to know the overall width and height and subtract half of their value from their respective top and left (e.g left: calc(50% - ([width of element] / 2)). Since you are using dynamic content you can't know either the height or the width (unless you make them static.)
So what can you do? There are a few ways, but my favorite at the moment is fairly new. It's called flexbox. It's support is decent. There's a nice snippet from css-tricks as well.
The relevant code to center an element both vertically and horizontally would go like this:
$(document).ready(function() {
$("button").click(function() {
$.get("http://lorem.mannfolio.com/", function(data) {
var lorem = data.split("\n\n");
$(".centered").html(lorem[0]);
});
});
});
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
html,
body {
height: 100%;
}
.container {
display: flex;
justify-content: center;
align-items: center;
height: 100%;
border: 1px solid black;
}
button {
position: fixed;
top: 10px;
left: 10px;
}
<button>Change text</button>
<div class="container">
<div class="centered">I'm centered No matter what you put in me.</div>
</div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
I'd like to make an image viewer that centers an image regardless of how big it is and allows scrolling to view the entire image.
The problem I'm running into is that, while centering images smaller than the container is easy, when they're larger tranform I'm doing positions the image off the right and top of the screen.
Here is the fiddle that has some fixup javascript to make it work: http://jsfiddle.net/d3y0b8bd/
The code below will work for smaller images (e.g. https://upload.wikimedia.org/wikipedia/meta/0/08/Wikipedia-logo-v2_1x.png)
But for larger, the translate(-50%, -50%) transform will translate the image past the left and top margins of its parent.
.lightboxRoot {
position: fixed;
width: 100%;
height: 100%;
overflow: auto;
/*aesthetic*/
background-color: red;
}
.lightboxImg {
position: absolute;
top: 50%;
left: 50%;
margin-right: -50%;
transform: translate(-50%, -50%);
/*aesthetic*/
background-color: blue;
}
html:
<div class="lightboxRoot">
<div class="lightboxImg">
<img id="imgElt" src="http://upload.wikimedia.org/wikipedia/commons/6/65/Cute_beagle_puppy_lilly.jpg"></img>
</div>
</div>
here's a fiddle in which JS is updating the position of scrollTop and scrollLeft, so to set the scroll to center of img.
Figured it out, in retrospect kind of silly: Just make a containing div that can't get any larger than the parent element, and make sure that it has the overflow property set so it gets the scrollbars. then the image inside can get is big as it wants: http://jsfiddle.net/abrady0/d3y0b8bd/2/
.lightboxRoot {
position: fixed;
width: 100%;
height: 100%;
/*aesthetic*/
background-color: red;
}
.lightboxContainer {
position: absolute;
top: 50%;
left: 50%;
margin-right: -50%;
transform: translate(-50%, -50%);
max-width: 90%;
max-height: 90%;
overflow: auto;
/*aesthetic*/
background-color: blue;
}
and the html:
<div class="lightboxRoot">
<div class="lightboxContainer">
<div>
<img id="imgElt" src="foo"></img>
</div>
</div>
</div>
one thing to fix in this case is that I'd still like the div's scroll centered with pure CSS, but this is a good first step.