Why is the header hiding in the mobile version? - javascript

Implemented the so-called "smart header", which hides when scrolling down and appears when scrolling up.
The problem: on the iPhone, I scrolled at the bottom, everything is ok hiding, but if I go back to the very top of the site, the header is hiding. It will appear only if you pull it down a little.
On the iPhone there is an animation when reaching the top of the screen, such as a rebound, I think it's about it. I tried safari, chrome, mozilla browsers. On android in chrome, everything is ok.
Tell me, has anyone encountered such a thing, how to treat it?
Sample code on Codepen
<div class="wrapper">
<div data-header class="header">
<p>header</p>
</div>
<div class="main">
<p>lorem ipsum</p>
<p>lorem ipsum</p>
<p>lorem ipsum</p>
<p>lorem ipsum</p>
<p>lorem ipsum</p>
<p>lorem ipsum</p>
<p>lorem ipsum</p>
<p>lorem ipsum</p>
<p>lorem ipsum</p>
</div>
</div>
.wrapper {
margin-top: -50px;
}
.header {
position: fixed;
width: 100%;
height: 70px;
top: 0;
left: 0;
text-align: center;
font-size: 25px;
background: red;
transition: transform .8s;
}
.header._hidden {
transform: translateY(-100%);
}
.main {
padding-top: 75px;
height: 100px;
}
let lastScroll = 0;
const header = document.querySelector('[data-header]');
const scrollPosition = () => window.pageYOffset || document.documentElement.scrollTop;
const containHide = () => header.classList.contains('_hidden');
window.addEventListener('scroll', () => {
if (scrollPosition() > lastScroll && !containHide()) {
header.classList.add('_hidden');
} else if (scrollPosition() < lastScroll && containHide()) {
header.classList.remove('_hidden');
}
Video with the problem on Yandex.Disk
I tried to make a negative margin on top to compensate a little did not help. No more ideas...

Related

Displaying a div inside a navbar with overflow-y: scroll

I'm trying to display a modal, the issue is the modal is inside a navbar which has the 'overflow-y' property set to 'scroll', which is making the value 'overflow-x' to 'auto', thus not allowing overflowing children on the x-asis, to be displayed. I'm looking for a way around this other than just moving the modal out of the navbar (It's not something that I can do for now). Is there a way via css to ignore the overflow-y property on the parent?
I made a fiddle with a similar case to the one I'm looking for: https://jsfiddle.net/aje31y7L/2/
<div class="background">
<nav class="navbar">
<div class="modal-wrapper">
<div class="modal-main">
</div>
</div>
</nav>
</div>
Currently the modal will appeared trimmed as part of it is hidden by the navbar. Any help is appreciated.
.background {
width: 100vw;
height: 100vh;
background-color: red;
position: relative;
}
.navbar {
display: block;
width: 400px;
left: -400px;
top: 0;
position: relative;
background: black;
max-height: 100%;
overflow-y: scroll;
transform: translateX(400px);
min-height: 100%;
}
.modal-wrapper {
display: flex;
position: relative;
align-items: center;
justify-content: center;
}
.modal-main {
display: flex;
height: auto;
background-color: grey;
}
h1{
font-size: 100px;
}
<div class="background">
<p>
lorem<br>
ipsum<br>
</p>
<nav class="navbar">
<div class="modal-wrapper">
<div class="modal-main">
<h1>
Lorem Ipsuim lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum
</h1>
</div>
</div>
</nav>
</div>
I have modified the code a little bit. As you run the snippet you will be able to see some text written in the div navbar in "p" tags but as soon as you erase the text inside "p" tags the div will go back in the background. Now as for the modal is concerned, I have modified the code too. The black background in the modal will not be visible but all the text inside it will be visible. It won't be chopped like before.

CSS transitions won't happen simultaneously after classList.toggle

I've been having this issue with a transition with a ReactJS accordion. Without seeing the problem I created this snippet in vanilla and happens the seame!
const acs = document.querySelectorAll('.accordion');
acs.forEach((a, i) => {
a.addEventListener('click', () => {
acs.forEach((aa, ii) => {
aa.classList.toggle('expanded', i === ii);
})
})
})
.accordion {
padding: 0.5em;
margin-bottom: 1em;
background: #f3f3f3;
}
.accordion p:last-child {
overflow: hidden;
margin: 0;
max-height: 0;
transition: 1s linear max-height;
}
.accordion.expanded p:last-child {
max-height: 100px;
}
<div class="accordion">
<p>toggle me</p>
<p>lorem ipsum</p>
</div>
<div class="accordion">
<p>toggle me</p>
<p>lorem ipsum</p>
</div>
<div class="accordion">
<p>toggle me</p>
<p>lorem ipsum</p>
</div>
Why transitions won't happen simultaneously? there's not setTimeout or transition-delay
Seems like I'm rusty with css transitions
-EDIT-
Noticed that if I apply transition on height instead it does work as expected but containers take more height than they need according to content. How can I achieve it with max-height?
const acs = document.querySelectorAll('.accordion');
acs.forEach((a, i) => {
a.addEventListener('click', () => {
acs.forEach((aa, ii) => {
aa.classList.toggle('expanded', i === ii);
})
})
})
.accordion {
padding: 0.5em;
margin-bottom: 1em;
background: #f3f3f3;
}
.accordion p:last-child {
overflow: hidden;
margin: 0;
height: 0;
transition: 1s linear height;
outline: 1px dashed red;
}
.accordion.expanded p:last-child {
height: 1em;
}
<div class="accordion">
<p>toggle me</p>
<p>lorem ipsum</p>
</div>
<div class="accordion">
<p>toggle me</p>
<p>lorem ipsum</p>
</div>
<div class="accordion">
<p>toggle me</p>
<p>lorem ipsum</p>
</div>
I think it is working - i.e. both transitions taking place at the same time - but you don't notice the beginning part of it transitioning down from 100px because there's nothing to show there (or rather, nothing to make not show). The amount showing in your example is not as big as 100px.
This snippet puts the max-height of 1.4em - which is enough to accommodate a line of the text - and you can see the transitions are taking place at the same time.
In your second example of transitioning the actual height of course you start to see the shinkage straightaway.
Here's the snippet with a reduced max-height as a demo:
const acs = document.querySelectorAll('.accordion');
acs.forEach((a, i) => {
a.addEventListener('click', () => {
acs.forEach((aa, ii) => {
aa.classList.toggle('expanded', i === ii);
})
})
})
.accordion {
padding: 0.5em;
margin-bottom: 1em;
background: #f3f3f3;
}
.accordion p:last-child {
overflow: hidden;
margin: 0;
max-height: 0;
transition: 1s linear max-height;
}
.accordion.expanded p:last-child {
max-height: 1.4em;
}
<div class="accordion">
<p>toggle me</p>
<p>lorem ipsum</p>
</div>
<div class="accordion">
<p>toggle me</p>
<p>lorem ipsum</p>
</div>
<div class="accordion">
<p>toggle me</p>
<p>lorem ipsum</p>
</div>

Replace css background-image: url(...) with <img> tag and keep scrolling over effect

I want to add alt tags to images on my website to improve SEO. The problem is I'm embedding them using CSS background-image: url(...).
It creates the desired scrolling effects (see below), but is not good for SEO.
Current code:
.text {
margin: 200px 20px;
}
.image-background {
background-attachment: fixed;
background-position: 50% 50%;
background-repeat: no-repeat;
background-size: 100%;
display: block;
height: 800px;
margin-bottom: 150px;
margin-left: -1500px;
margin-right: -1500px;
margin-top: 150px;
width: 3500px;
}
.image1 {
background-image: url(https://i.ytimg.com/vi/tntOCGkgt98/maxresdefault.jpg);
}
.image2 {
background-image: url(http://media1.santabanta.com/full1/Animals/Cats/cats-149a.jpg);
}
<div class='text'>
Lorem ipsum dolores...
</div>
<div class='image-background image1'></div>
<div class='text'>
Lorem ipsum dolores...
</div>
<div class='image-background image2'></div>
<div class='text'>
Lorem ipsum dolores...
</div>
The question is: how do I add <img> tags with alt properties without breaking the visual appearance?
Edit:
I tried using <img> with css position:fixed but can't get it to work well with more than one image (my broken jsfiddle here).
Edit 2:
These images are part of website content, not layout. They deserve alt tags, I'm not trying to stuff more keywords in a "bad" way. I originally put them as backgrounds to achieve a visual effect. Now I want to fix the mistake, but without changing how the website looks like.
I'm talking about my photos on this blog.
Edit 3:
I'm not trying to use only CSS here. Any code modification, JS library or pretty much anything is fine!
Method 1
This method doesn't change the visibility of the images, so I think there's no issues about SEO at all. But it is more complex and have the caveat that only one image can appear per once. So the text's div must to fill the entire screen resulting in a big padding.
$(function(){
var texts = $('.text');
var oldY = 0;
$(document).scroll(function(){
var y = window.scrollY;
texts.each(function(){
var text = $(this);
if(y >= text.offset().top)
text.next().addClass('active');
else
text.next().removeClass('active');
});
});
});
body{
padding: 0;
margin: 0;
}
.text{
padding: 20px;
margin: 0 0 600px;
position: relative;
z-index: 3;
background-color: #fff;
min-height: 100vh;
display: flex;
align-items: center;
}
.background-img img{
position: fixed;
top: 0;
left: 0;
z-index: 1;
width: 100%;
}
.background-img.active img{
z-index: 2;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js"></script>
<div class='text'>
Lorem ipsum dolores...
</div>
<div class="background-img active">
<img src="https://i.ytimg.com/vi/tntOCGkgt98/maxresdefault.jpg" alt="Image 1">
</div>
<div class='text'>
Lorem ipsum dolores...
</div>
<div class="background-img">
<img src="http://media1.santabanta.com/full1/Animals/Cats/cats-149a.jpg" class="background-img" alt="Image 2">
</div>
<div class='text'>
Lorem ipsum dolores...
</div>
Method 2
This is simpler, and to say the truth it's almost the same idea from your original code. The difference is that as soon as the page loads, the images are hidden and then copied as background images for their parent divs. The advantage is that you can have more then one image visible at the same time, which is a better effect.
$(function(){
$('.background-img img').each(function(){
var img = $(this).hide();
img.parent().css('background-image', 'url(' + img.prop('src') + ')');
});
});
body{
padding: 0;
margin: 0;
}
.text{
padding: 200px 20px;
position: relative;
z-index: 3;
background-color: #fff;
}
.background-img{
height: 400px;
background-attachment: fixed;
background-repeat: no-repeat;
background-position: center;
background-size: 100%;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js"></script>
<div class='text'>
Lorem ipsum dolores...
</div>
<div class="background-img">
<img src="https://i.ytimg.com/vi/tntOCGkgt98/maxresdefault.jpg" alt="Image 1">
</div>
<div class='text'>
Lorem ipsum dolores...
</div>
<div class="background-img">
<img src="http://media1.santabanta.com/full1/Animals/Cats/cats-149a.jpg" class="background-img" alt="Image 2">
</div>
<div class='text'>
Lorem ipsum dolores...
</div>

HTML/CSS - How to place left and right divs outside container?

I'm developing a site built with Ribosome theme. What I would like are 3 divs outside the main container which has a responsive width, but I'm not sure how to get this done properly.
I want it to look something like this
I accomplished the above image by creating an invisible div between the left and right divs, that pushes them to the sides. I feel like this is a bad way to do it as it requires JavaScript or CSS to set the right width of the invisible div between them. The top div is placed inside the container, so it uses its width. This was the code:
<div class="outside-mid" style="background-color:#333;width:100%;height:300px;">Lorem ipsum dolor sit amet.</div>
<div id="outside-container" style="position:absolute;text-align:center;height:0;width:1144px;">
<div class="outside-left" style="background-color:#333;width:300px;height:600px;float:left;margin-left:-310px;">Lorem ipsum dolor sit amet.</div>
<div class="outside-right" style="background-color:#333;width:300px;height:600px;float:right;margin-right:-310px;">Lorem ipsum dolor sit amet.</div>
</div>
I set the width of outside-container using JS:
<script>
var width = document.getElementById('main').offsetWidth;
document.getElementById("outside-container").style.width = width + "px";
</script>
What I'm asking is if there's a way to just put the left and right divs inside the container and then, without using any invisible div to push them, just float them to the left and to the right outside the container. This way it would end up being responsive as it would always use the container width.
Set your html to look like this..
<div id="outside-container">
<div class="outside-left"></div>
<div class="main-div"></div>
<div class="outside-right"></div>
</div>
and try this css..
#outside-container { width: 100%; }
.outside-left { width: 20%; float: left; }
.outside-right { width: 20%; float: right; }
.main-div { width: 60%; float: left; }
please you can use this code.
Lorem ipsum dolor sit amet.
<div id="outside-container" style=" background: rgba(0, 0, 0, 0.5) none repeat scroll 0 0;display: table; height: 0; margin: 0 auto; text-align: center; width: 1144px;">
<div class="outside-left" style=" background-color: #333333;float: left; height: 600px; transform: translateX(-100%); width: 300px;">Lorem ipsum dolor sit amet.</div>
<div class="outside-right" style="background-color: #333333; display: inline-block; float: right; height: 600px; margin: 0 auto; transform: translateX(100%); width: 300px;">Lorem ipsum dolor sit amet.</div>
</div>
A lot of good answers here, but I found them quite hard to implement with the use of the same theme I already had installed. After looking through more solutions I found a way that worked for my case. I put the following inside the container, and it worked without altering the current layout.
<style>
#left:before, #right:before, #top:before {
position:absolute;
content: "Ads";
top:-20px;
color: #fff;
}
#left:before {
right:0;
}
.site {
overflow:visible;
position:relative;
top:340px;
}
</style>
<div id="top" style="position: absolute; width:100%; height:300px; top:0; background-color:#888;margin-top:-310px;"></div>
<div id="left" style="position: absolute; width:300px; height:600px; left: 0; top: 0; background-color:#888;margin-left:-310px;"></div>
<div id="right" style="position: absolute; width:300px; height:600px; right: 0; top: 0; background-color:#888;margin-right:-310px;"></div>
Note: .site refers to the parent (container)

Set multiple div elements to "position: fixed" at the bottom of a page

I have 4 div on my page. I want to set those 4 div at bottom, so that those div stay at bottom even when there are scrollbar.
This is my HTML.
<div id="content">
1) Lorum Ipsum Dolor Sit Amet<br />
Lorum Ipsum Dolor Sit <br />
Lorum Ipsum Dolor Sit <br />
Lorum Ipsum Dolor Sit <br />
Lorum Ipsum Dolor Sit <br />
Lorum Ipsum Dolor Sit <br />
Lorum Ipsum Dolor Sit <br />
Long Dummy content.
</div>
<div class="footerdiv">Footer - scroll 1</div>
<div class="footerdiv">Footer - scroll2</div>
<div class="footerdiv">Footer - scroll 3</div>
<div class="footerdiv">Footer - scroll4</div>
And my Css
.footerdiv {
position: fixed;
bottom: 0;
width: 100px;
}
It is setting my div at bottom, But all the bottom div are overlapping.
I want to show them side by side by keeping all 4 div at bottom.
JsFiddle
Rather than positioning each element at the bottom, wrap the elements and set the parent element's position to fixed and position it at the bottom.
In doing so, the .footerdiv elements are still in the normal flow, and they can be positioned beside each other.
Updated Example
.footer-container {
position: fixed;
left: 0; right: 0;
bottom: 0;
}
.footer-container .footerdiv {
display: inline-block;
}
You had actually used 4 div's with same DIV id.
This is what you had to do-
<div class="footerdiv">
<div>Footer - scroll 1</div>
<div>Footer - scroll2</div>
<div>Footer - scroll 3</div>
<div>Footer - scroll4</div>
</div>
and set css to 100%, let it take up the horizontal space of the page-
.footerdiv {
position: fixed;
bottom: 0;
width: 100%;
}
Have a look at the working demo on JS fiddle.
Hope it helps :) Happy coding!
Set an id for each div and refer to each div that way.
<div class="footerdiv" id = "d1">Footer - scroll 1</div>
<div class="footerdiv" id = "d2">Footer - scroll2</div>
<div class="footerdiv" id = "d3">Footer - scroll 3</div>
<div class="footerdiv" id = "d4">Footer - scroll4</div>
Then you can say:
.footerdiv {
position: fixed;
bottom: 0;
}
#d1 {
left: 100px;
}
#d2 {
left: 200px;
}
#d3 {
left: 300px;
}
How about a table? You can create a new column for each one of your elements.
<table class="footerdiv">
<tr>
<td>Footer - scroll 1</td>
<td>Footer - scroll 2</td>
<td>Footer - scroll 3</td>
<td>Footer - scroll 4</td>
</tr>
</table>
You can wrap them in footer like this. Here is fixed version:
https://jsfiddle.net/4dq215h4/2/
and change css to this:
.footerdiv {
background: #0070FF;
line-height: 2;
text-align: center;
color: #042E64;
font-size: 20px;
font-family: sans-serif;
text-shadow: 0 1px 0 #84BAFF;
box-shadow: 0 0 15px #00214B;
display:inline-block;
float:left;
width:100px;
}
footer{
position:fixed;
bottom:10px;
}

Categories