My document is using browser-native smooth scroll behavior defined via CSS (and not javascript) and anchor links to scroll down to a specified part of the page when clicked on.
This works fine except that the top of the page the anchors are located at end up hidden underneath the sticky nav bar that is fixed to the top of the screen after the animated scroll has finished. I therefore need to offset the scroll's destination Y coordinate.
Example (when you click):
#media ( prefers-reduced-motion: no-preference ) {
html {
scroll-behavior: smooth;
}
}
nav {
position: fixed;
top: 0;
background-color: rgba(204, 204, 204, 0.9);
padding: 1rem;
text-align: center;
width: 100%;
}
body {
margin: 0;
}
main {
margin: 4rem 1rem 120vh;
}
<nav>Nav Bar</nav>
<main>
Example Anchor Link
<br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br>
<p id="example">Scroll Target</p>
</main>
Is there a way to offset the scroll target so that it's not covered up by the nav bar? I don't think there is a javascript event that fires when the browser's scroll animation has completed. I also haven't seen a way to customize the browser's animation duration.
I just stumbled upon this question...
The answer is pretty simple, you can always give some padding top to the target element, in this case for instance 60px of padding 👇 since the nav bar is 50px in height. This will act as an offset.
#media ( prefers-reduced-motion: no-preference ) {
html {
scroll-behavior: smooth;
}
}
nav {
position: fixed;
top: 0;
background-color: rgba(204, 204, 204, 0.9);
padding: 1rem;
text-align: center;
width: 100%;
}
body {
margin: 0;
}
main {
margin: 4rem 1rem 120vh;
}
<nav>Nav Bar</nav>
<main>
Example Anchor Link
<br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br>
<p id="example" style="padding-top: 60px;">Scroll Target</p>
</main>
Related
Hey out there reading,
i'm making a webpage and im relativly new to JavaScript. I want the Navbar to change Color when its in section Two, while in Section One and Three the Navbar should have the same Color. I watched some tutorials and was able with that code to change the color of the navbar so that in section one and section two the navbar has the right color. When trying out the variables sectionTwo and sectionThree (in order to get the navbars Color to switch back to the color in sectionOne when entering sectionThree) on the other hand it didnt change the colors at the right position (like 100px befor the section). I dont know why this problem accures. If someone knows how to fix it, it would mean the world to me :).
const header = document.querySelector("header")
const sectionOne = document.querySelector(".one")
const sectionTwo = document.querySelector(".two")
const sectionThree = document.querySelector(".three")
const sectionOneOptions = {
}
const sectionOneObserver = new IntersectionObserver(function(entries, sectionOneObserver) {
entries.forEach(entry => {
if (entry.isIntersecting) {
header.classList.add("nav-scrolled")
} else {
header.classList.remove("nav-scrolled")
}
});
},
sectionOneOptions);
sectionOneObserver.observe(sectionTwo)
* {
margin: 0;
padding: 0;
box-sizing: border-box;
font-family: "Arial";
}
body {
width: 100vw;
height: 100vh;
margin: 0;
background: #000;
}
header {
--text: #fff;
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 8rem;
z-index: 10000;
padding: 0 1rem 5rem;
display: flex;
justify-content: space-between;
align-items: center;
}
header nav {
margin: auto;
display: flex;
justify-content: center;
align-items: center;
}
header nav li {
flex: 0 0 auto;
list-style: none;
margin-left: 1rem;
}
header nav li a {
text-decoration: none;
padding: 6px, 15px;
color: var(--text);
border-radius: 20px;
}
.nav-scrolled {
--text: #000;
}
.one {
position: relative;
width: 100%;
height: 100vh;
padding: 200px 20vw;
display: flex;
}
.two {
height: 100vh;
position: relative;
padding: 100px 20vw;
background: #fff;
}
.three {
position: relative;
padding: 100px 20vw;
color: #fff;
height: 100vh;
}
<html>
<head>
<link rel="stylesheet" type="text/css" href="style.css" />
</head>
<body>
<header>
<nav>
<li>one</li>
<li>two</li>
<li>three</li>
</nav>
</header>
<section>
<div class="one" id="one"></div>
</section>
<section>
<div class="two" id="two"></div>
</section>
<section>
<div class="three" id="three"></div>
</section>
<script src="app.js"></script>
</body>
</html>
Let me know if you need some more Code and not only the snippet to fix this.
Hopefully some hero can help me :).
Greetings
Noel
I did research to try and answer this question, so please take the preface that I am not an expert in IntersectionObserver.
With that preface out of the way,
There were many things I changed from your example to create the desired effect, however the core feature that you would have needed to implement in your example is the option for intersection observers, rootMargin. By adding this option you can give the item on the screen a negative top and bottom margin. This is important, because you do not want the observer to fire until the header is about to cross into the observed section, and you dont want the header to change until just before it crosses back into the next section.
The way I chose to emulate this behavior, is by using the rootMargin option to give a negative margin. This makes the actual element observed begin however many pixels after we specify. For example, an element that is 100px in height, with "0px 0px -20px 0px" as the value for rootMargin in the options object, would not trigger the IntersectionObserver until 20px of the element was scrolled into the viewport height.
With this understanding, we can define our goal. We want to preform an action when the observed element is about to touch the header. We can describe this as the viewport height minus the header height in a negative margin to the bottom would adjust the element just enough to trigger the intersection observer as desired. Because the methods of obtaining margins are not exact, I subtract one from the numbers calculated to adjust for small error. If we set both margins to overlap eachother, we will never have the observer fire.
I also decided to use css variables and set the value of the variable depending on whether or not the element observed scrolled into or out of the viewport.
This code is not able to execute properly in a stack snippet because the viewport option that the intersection observer defaults to in the options is not set correctly for the snippet environment. I have not tested this code in environments that resize.
Hopefully that explanation helps you understand this code. Let me know if you have any questions.
relevant html:
<header>
<nav>
<li>one</li>
<li>two</li>
<li>three</li>
</nav>
</header>
<section id="one">
</section>
<section id="two">
</section>
<section id="three">
</section>
<script src="app.js"></script>
relevant css:
:root {
--header-text-color: white;
}
body {
margin: 0;
}
header {
position: fixed;
top: 0;
width: 100%;
}
header nav {
display: flex;
justify-content: center;
align-items: center;
}
header li {
list-style: none;
padding: 1rem;
font-size: 2rem;
}
header a {
color: var(--header-text-color);
text-decoration: none;
}
section {
height: 120vh;
background: black;
}
#two {
background: white;
}
relevant js:
const header = document.querySelector("header");
const sectionTwo = document.querySelector("#two");
const topMargin = header.offsetHeight - 1;
const bottomMargin = window.innerHeight - header.offsetHeight - 1;
const options = {
rootMargin: `-${topMargin}px 0px -${bottomMargin}px 0px`,
}
const observer = new IntersectionObserver(([entry]) => {
const color = entry.isIntersecting ? "black" : "white";
document.documentElement.style.setProperty('--header-text-color', color);
}, options);
observer.observe(sectionTwo);
I am using Bootstrap 4 on my project, and modified the modal style in order to make it fullscreen like you can see it on this css code:
.modal.show {
display:flex!important;
flex-direction:column;
justify-content:center;
align-content:center;
align-items: flex-start;
}
.modal-body {
padding: 0;
margin: 0;
}
.close {
color: #aaa;
position: absolute;
/* background: blue !important; */
border: 0;
top: 0;
z-index: 99999;
right: 3%;
float: none;
opacity: 1;
font-size: 40px;
font-weight: 400;
}
.modal-backdrop.modal-backdrop-transparent {
background: #ffffff;
}
.modal-backdrop.modal-backdrop-transparent.in {
opacity: .9;
filter: alpha(opacity=90);
}
.modal-backdrop.modal-backdrop-fullscreen {
background: #ffffff;
}
.modal-backdrop.modal-backdrop-fullscreen.in {
opacity: .97;
filter: alpha(opacity=97);
}
.modal-fullscreen {
background: #fff;
min-width: 100%;
margin: 0;
}
#media (min-width: 768px) {
.modal-fullscreen .modal-dialog {
width: 750px;
}
}
#media (min-width: 992px) {
.modal-fullscreen .modal-dialog {
width: 970px;
}
}
#media (min-width: 1200px) {
.modal-fullscreen .modal-dialog {
width: 100%;
}
}
.modal-dialog {
position:fixed;
padding: 0;
max-width: 100%;
margin: 0;
top: 0;
bottom: 0;
left: 0;
right: 0;
height: 100vh;
overflow:auto;
}
When I tried to scroll down the vertical scrollbar of the browser, it won't ! I can use mouse scroll wheel but not by clicking on it directly !
Are you able to detect the problem ? It's for sure the fixed position but it is needed to make it fullscreen.
Here a jsfiddle to see a live demo of the problem:
https://jsfiddle.net/odbjcpt2/1/
I don't want to use position FLEX instead of FIXED since it won't solve the problem on my project, even if in the example given it will works (modal keep ading padding-right to body ... it is fixed using FIXED).
Thank you
In your JSFiddle, the problem appears to be with the div that contains the Lorem Ipsum text. It has pointer-events: auto; inherited from .modal-content class and if you remove that it ends up with pointer-events: none; inherited from modal-dialog class. If you take both those away, the problem goes away.
EDIT
I believe the root of the issue is that you're setting your .modal-dialog class to have fixed position and overflow auto.
Below is from bootstrap doc
Modals use position: fixed, which can sometimes be a bit particular
about its rendering. Whenever possible, place your modal HTML in a
top-level position to avoid potential interference from other
elements. You’ll likely run into issues when nesting a .modal within
another fixed element.
After playing around, if I edit your CSS in your JSFiddle example and in the .modal-dialog class I just remove position:fixed; and overflow:auto;, the problem goes away.
EDIT AGAIN
I just noticed you actually have .modal-dialog defined in your CSS twice, the first time with flex position and second time with fixed. Sounds like that was maybe a copy/paste mistake. Anyhow, still the same root cause I think, because your .modal-dialog div is fixed and it's inside your .modal div, and bootstrap doc says don't put another fixed inside a .modal
I've this code here (Please open in expanded mode):
#wrapper {
position: fixed;
background: gray;
color: #fff;
bottom: 0;
left: 0;
right: 0;
border-radius: 12px 12px 0 0;
width: 100%;
}
#title {
text-align: center;
padding: 15px;
border-bottom: 1px solid white;
}
#notifications {
display: flex;
flex-direction: column;
overflow: scroll;
overflow-x: hidden;
}
.entry {
padding: 15px;
}
<div id="wrapper">
<div id="title">Notifications</div>
<div id="notifications">
<div class="entry">Test</div>
<div class="entry">Test</div>
<div class="entry">Test</div>
<div class="entry">Test</div>
<div class="entry">Test</div>
<div class="entry">Test</div>
<div class="entry">Test</div>
</div>
</div>
It should be like in Google Maps when you explore the nearby. So like a slide up div from the bottom. The title should be visible when it's not expanded but not the notifications. When I click the title, I want to smoothly expand the element up to 85 percent of the viewport so that the user can scroll trough the notifications. When he clicks the title again, it should go back down to the initial state.
Is this possible? If yes, how?
To change between two states, expanded and collapsed, you'll need some kind of JavaScript.
As far as the CSS, I'd suggest for #wrapper instead of using bottom: 0, using something like top: calc(100% - 42px) (the 42px should be whatever the height you want to be visible) for the collapsed state, and then top: 15% for the expanded state.
For the "smooth" part of it, you just need to add a transition animation.
Here's a basic codepen showing what I mean: https://codepen.io/milesgrover/pen/gOpbrpd
I want to create a website with a single fixed-width centered column and an additional fixed-width sidebar that is position: fixed on the left. When the window is large, this works perfectly, but when I resize the window, they begin to overlap when there's plenty of room left on the right side of the window. For example:
I'd like the center div to be positioned in the center until it runs into the sidebar, at which point I'd like it to have a more fluid responsive design, where the sidebar starts to push the div to the right as you resize the window. For example:
The only solution I'm aware of is something like this (using the jQuery resize event and adding a class to the center column when the window resizes small enough):
var SMALL_WINDOW_SIZE = 560;
function checkWindowSize() {
var $content = $("#content");
if ($(this).width() < SMALL_WINDOW_SIZE && !$content.hasClass("smallWindow")) {
$content.addClass("smallWindow");
} else if ($(this).width() >= SMALL_WINDOW_SIZE && $content.hasClass("smallWindow")) {
$content.removeClass("smallWindow");
}
}
$(document).ready(function() {
checkWindowSize();
});
$(window).resize(function() {
checkWindowSize();
});
#sidebar {
background: orange;
width: 100px;
height: 200px;
position: fixed;
top: 10px;
left: 10px;
}
#content {
background: blue;
width: 300px;
height: 350px;
margin: 0px auto;
}
.smallWindow {
float: left;
margin-left: 120px !important;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div id='sidebar'></div>
<div id="content"></div>
I can't help but feel there should be a pure CSS solution or one that uses less or more elegant JavaScript. Is there such a thing?
This isn't by any means the best way of achieving the desired effect with CSS, but it's the methodology behind using CSS media queries to adapt layout that I want to convey.
Obviously if this meets your needs, you'll want to adjust the numbers/widths to suit your case.
*, :before, :after{
box-sizing: border-box;
}
body {
margin: 0;
}
.wrapper {
position: relative;
padding: 20px;
}
.sidebar, .main {
padding: 20px
}
.sidebar {
position: fixed;
top: 20px;
left: 20px;
width: 200px;
background: goldenrod;
color: white;
height: 50vh;
}
.main {
margin-left: 220px;
background: mediumblue;
color: white;
height: 200vh;
}
#media (min-width: 1050px){
.main{
margin: 0 220px 0 220px;
}
}
<div class="wrapper">
<div class="sidebar">
Sidebar
</div>
<div class="main">
Main
</div>
</div>
» JSBin
There's a mysterious whitespace along the right of my site in firefox (on both PC and Mac, latest versions) and I can't for the life of me figure out what's causing it.
This is what it looks like -
I've been searching the CSS for ages now trying to figure out if it's some margin or padding issue but I can't find anything.
Also, if I remove the div ID 'slider3' the issue seems to disappear, yet I can't figure out how this div is causing the whitespace, since it has no CSS applied to it - it's simply a container.
Here's my site http://www.simplerweb.co.uk
Here's some relevant code so the answer is useful for people later on.
<div class="fullw">
<div class="sliderleft"></div>
<div class="sliderright"></div>
<div id="slider3">
<div class="quote">
<div class="centmid">
<h1 class="fronth">Hello</h1>
<h2 class="frontp">Welcome to Simpler Web</h2>
<h2 class="frontp2">We're an Edinburgh based Web<br> Design Agency</h2>
</div><!-- end div centmid -->
</div> <!-- end div quotes1 -->
<div class="quote2">
<div class="centmid">
<h2 class="frontb">We make wonderful, cross platform <br> accessible Websites </h2>
</div> <!-- end div centmid -->
</div> <!-- end div quotes2 -->
<div class="quote3">
<div class="centmid">
<h2 class="frontc">We can translate your ideas into reality </h2>
</div> <!-- end div centmid -->
</div><!-- end div quotes3 -->
</div> <!-- #slider3 -->
</div>
CSS
/* The following styles are essential to the slider's functionality */
.plusslider {
overflow: hidden;
position: relative;
padding-top: 140px; /* The height / width of the slider should never be set via the CSS. The padding increases the slider box-model while keeping it dynamic */
}
.plusslider-container { position: relative; }
/* Slides must have a set width - even though they may be dynamic. If no width is set on <img> slides, the default image size will be assumed */
div.child { width: 480px; }
.plusslider .child { float: left; }
/* PlusFader Specific (not needed with plustype:slider */
.plustype-fader .child { display: none; position: absolute; left: 0; top: 0; }
.plustype-fader .current { z-index: 5; }
/* End PlusFader Specific */
/* No-javascript fallback -- change "#slider" and "#slider2" identifiers as needed for your html */
#slider > * { display: none; }
#slider > *:first-child, #slider2 > *:first-child { display: block; }
/* End no-javascript fallback */
/* End essential styles*/
/* The following styles are not essential for slider functionality. They are specific to the example content.
It is important to note that the fading effect does not work correctly with non-image content unless that
content area has a solid background (either a background image or a background-color, but not transparent).
Slides to not have to be the same width or height, but if you'd like a consistent width and/or height, make sure to set that within the CSS! */
#slider .slide1 { padding-left: 40px; padding-right: 40px; margin-left: 0; margin-right: 0; }
#slider .slide1 { height: 210px; padding-top: 20px; padding-bottom: 20px; margin-top: 0; margin-bottom: 0; }
.slide1 { height: 500px; padding: 20px 40px; }
.slide1 h2 { color: #fff; font-size: 20px; margin: 0 0 20px 0; text-align: left; }
.slide1 p { border-left: 3px solid #fff; color: #fff; padding: 0 0 0 10px; }
.quote, .quote2, .quote3 { height:400px; padding: 20px 0; width: 980px; width: 100%; position: relative; }
.quote { background-image: url(../images/weare.png); background-position: center; background-repeat: no-repeat; }
.quote2 { background-image: url(../images/headlogosandroid.png); background-position: center; background-repeat: no-repeat; }
.quote3 { background-image: url(../images/ideafront.png); background-position: center; background-repeat: no-repeat; }
.plusslider a img { border: none; } /* Prevent blue borders in IE (not only does it look ugly, but it messes up spacing which breaks the "slider" type */
.plusslider-pagination { position: absolute; left: 0; bottom: 0; }
.plusslider-pagination li { float: left; list-style: none; margin-left: 5px; }
#slider3 {margin: 0; padding: 0;}
You have (in FF) exactly 17px extra width that is exactly the width of the browser scrollbar.
Your starting (initial) loading black screen (that animates) leaves a glitch of 17px:
cause it's animation maintains the DOM width that equals the screen width without the right scrollbar (100% screen width).
After the page is fully loaded and the scrollbar is added to the page, it actually adds the extra 17px (to the 100%) width that were maintained by the Loading animation.
Hope I put you in the right direction.
By the way, try to add:
html {
overflow-y: scroll;
}
and - if still needed - adjust the loading element width as I mentioned before.
Add this:
body{
overflow-x: hidden;
}
Problem solved. (temporarily)
So where is the problem?
It is at your <div> with the classes plusslider slider3 plustype-slider. You are constantly setting an incorrect width to it. You have to subtract the scrollbar width.
You can also try to do this: Padding: 0px(or whatever) 17px; and margin: 0px(or whatever) -17px; now your whitespace at the sides are gone.