After way too much time agonizing over the breakage of a simple sticky sidebar component I've used without issue on numerous projects, I identified a partial solution that caused other issues.
This sidebar makes use of flexbox to keep the sidebar in place and treat a container div like the body of the page.
Unfortunately, it broke as soon as I started using it in Vue.js. I initially assumed it was because the element heights were not responding to dynamically populated content, but this is not the case.
The wrapper structure looks like so:
<html>
<body>
<div class="wrapper">
<div id="sidebar>
</div>
<div class="container">
</div>
</div>
</body>
</html>
And the CSS:
html {
position: relative;
height: 100%;
box-sizing: border-box;
width: 100%;
overflow-x: hidden;
height: 100%;
}
body {
overflow-x: hidden;
margin: 0;
min-height: 100%;
position: relative;
background-size: 100vw 100vh;
background-attachment: fixed !important;
width: 100%;
}
.wrapper {
display: flex;
align-items: stretch;
}
#sidebar {
height: 100vh;
position: sticky;
position: -webkit-sticky;
}
.container {
width: 100%;
margin-right: auto;
margin-left: auto;
}
NB: I did successfully cause the sidebar to look like it was sticking by setting the body height to 100%, but the actual links still scrolled, even though you could see the sidebar. Furthermore, this broke the layout properties of the Flatpickr datepicker being used on one of the most important pages in the site. Obviously, this is not a tenable solution, because a visible but interaction-less sidebar is useless, and I need my pages to actually work.
To be clear-- I chose to use sticky rather than fixed because I wanted to take advantage of flexbox to set the page content's container effectively next to the sidebar, rather than simply pushing it over using margin to keep it from being overlaid by the sidebar.
Here's a (messy, I apologize-- it's pulled out of a muuuuuuuch larger project) Codesandbox to show you the sidebar in context.
https://codesandbox.io/s/8897m88kl
Related
I have a React application with this basic layout:
function App() {
return (
<div className="app">
<Header />
<Main />
<Footer />
</div>
);
}
export default App;
My issue is that I have separate stylesheets for each of these components, but I can't get my footer to both be at the bottom of the page, and always stay below content. That is, if the page is blank, the footer would still be at the bottom, and if there was content that was larger than the viewport height, the footer would still remain under it.
I've seen answers to this issue, but only with regular HTML pages, not with different React components with different stylesheets. I have an index.css, App.css, and CSS pages for each of my App components.
Is there a way I should go about it? Which stylesheet should I add the code to have the footer stay at the bottom and below the content. I currently have code in my Footer.css, but the code doesn't keep the footer at the bottom of the page and below content.
I think the issue is that usually all the components are on the same HTML page within the body, but React is broken up a little differently. Any help would be great.
You could add the below lines inside index.css for example. You can change auto to a fixed value if you want, like 100px.
.app {
min-height: 100vh;
display: grid;
grid-template-rows: auto 1fr auto;
gap: 3rem;
}
That would do the job. Additionally you can make sure there isn't some padding or margin coming from the outside, I mean the div with root id, body and html, to avoid any unnecessary horizontal scroll.
You need to add style to global container:
html,body,#root {
display: flex;
flex-direction: column;
min-height: 100%;
}
then add style to your footer component:
.footer {
padding-top: auto;
}
I won't recommend using
min-height: 100vh;
it will break on mobile, because of how its calculated.
In index.css add this:
Footer {
width: 300px;
text-align: center;
position: relative;
bottom: 0;
left: 50%;
-webkit-transform: translate(-50%, 0);
transform: translate(-50%, 0);
}
Example: https://codesandbox.io/embed/quirky-sound-bitt9k?fontsize=14&hidenavigation=1&theme=dark
You can change position: fixed; if you want the footer section to show at the bottom of the page relative to the viewport, rather than relative to the page content.
Sources for your reference:
https://getridbug.com/html/transform-translate-50-50/
https://www.w3schools.com/css/css_positioning.asp
I was having an issue using grid and grid-template-rows, but switching to flex did the trick.
My understanding is that using a flex-direction: column; and justify-content: space-between; spaces my three components and forces my <Footer /> underneath <Main /> no matter the viewport height.
If anyone has a better understanding of why my answer works better than others, I'd love an explanation.
index.css file:
.app {
min-height: 100%;
display: flex;
flex-direction: column;
justify-content: space-between;
}
Im trying to get this scrolling effect i have seen on the website http://www.unheap.com , if you scroll to the bottom or to the right you'll notice that you can't scroll past whatsoever. Most website including this one allow you to scroll past slightly with a lot of resistance but I'm trying to replicate the example above where you can't scroll past at all. Anyone know of any plugins or methods on how to go about creating this effect?
The actual website itself is 100% the width and height of the page and any scrolling that occurs is accomplished via an absolutely positioned container with overflow: scroll.
EDIT
The actual overflow is set on the .grid element, which is inside the absolutely positioned .container element.
EDIT #2
The author is also using jScrollPane, but you can prevent the bouncing effect simply by making your body 100% width and height and absolutely positioning a container that has overflow set to scroll.
EDIT #3
See the attached code snippet - (you may have to copy and paste it into it's own HTML file because of the way SO displays snippets). There is no bouncing.
* { margin:0; padding:0; }
html,
body { width: 100%; height: 100%; overflow:hidden;}
body>div { height: 50vh; overflow: auto; padding: 10px; background: #000; position: absolute; width: 100px; top: 100px; left: 100px;}
body>div>div { height: 1000px; background: #0f0;}
<div>
<div>scrollable content</div>
</div>
Here is a fiddle to demonstrate the problem:
http://jsfiddle.net/6e1vg58L/
The javascript adds the "position:fixed" to the nav-content. Everything works how I want, the nav content stays in place while scrolling down the page. Now, if you go and put "position: fixed" under "#nav-content" in the CSS, and delete the JS, it should have the same outcome, correct?
For some reason setting the position in CSS or HTML causes the entire cell to dissapear, while setting it using Javascript or any browser inspector gives it the desired output?
$(document).on("scroll", function(){
if($(window).scrollTop() > 0)
{
$("#nav-content").css("position","fixed");
}
else
{
$("#nav-content").css("position","relative");
$("#nav-content").css("top",0);
}
});
vs
#nav-content {
position: fixed;
}
At first I thought it could be something with the listener causing it to work (but why?), but after opening it up in a live browser and adding the "position: fixed" through the inspector, it works exactly how it should. This is the problem, two out of four ways give the same, desired result, but the other two give the same, undesired result.
Although I am not 100% on the exact whys I think the reason is because by declaring it fixed has the following effect.
fixed
Do not leave space for the element. Instead, position it at a
specified position
so it means content being 100% is allowed to take the whole screen when the page is first rendered. Navigation (although not the one being fixed which is the confusing bit) is on the screen but hidden by the content at 100%. the interesting thing is if you use chrome to disable the fixed property the navigation appears and then because it is now on screen reapplying the position fixed does not hide it which is why the JS route behaves differently.
the changes to fix could defining the initial widths in % relative to each other.
#content {
position: relative;
background-color: #eee;
width: 70%;
max-width: 1300px;
min-width: 450px;
height: auto;
}
and then the same for navigation
#navigation {
width: 30%;
background-color: #000;
height: 100%;
position: relative;
top: 0;
bottom: 0;
}
http://jsfiddle.net/vemtyyox/
another way to keep the navigation at 300px could be to use calc to define the width of the content
#content {
position: relative;
background-color: #eee;
width: calc(100% - 300px);
max-width: 1300px;
min-width: 450px;
height: auto;
}
#navigation {
width: 300px;
background-color: #000;
height: 100%;
position: relative;
top: 0;
bottom: 0;
}
http://jsfiddle.net/9db77jvp/
Looking closer i think there is something odd about the way display:table-cell and the fixed properties are working, maybe.
I'm trying to make an effect similar as used on http://www.t-mobile.com/ , when the user scrolls down to the bottom of the page they reveal the "footer" more and more as the user keeps on scrolling.
I've tried to search both here and on google but haven't been able to find anything that's really useful. Most examples only shows/hide the footer once the user scrolls to the bottom.
So my question is, what's the effect called to reveal an element by scrolling? Are there any good tutorials / blog posts about this? All help I can get is much appreciated!
As I commented, you need to make your element fixed, so as explanation goes, I have two elements here, one is a normal position: relative; element, so nothing fancy about that, I assigned relative so that I can make the z-index work
Second element is positioned fixed and also, make sure you use margin-bottom which should be equal to the height of your footer, no need to assign any negative z-index whatsoever to this element.
Demo
Not much HTML ...
<div></div>
<div>Reveal Me</div>
CSS
/* These are for your main site wrapper */
div:first-child {
height: 800px; /* Even auto is fine, I
used fixed height because I don't have any content here */
background: #eee;
margin-bottom: 200px; /* Equals footer wrappers height */
z-index: 1;
position: relative;
}
/* These are for footer wrapper */
div:last-child {
background: #aaa;
height: 200px;
position: fixed;
bottom: 0;
width: 100%;
}
For Dynamic Sizes
Note that am using a fixed height for the fixed positioned element, if you have variable height in footer element, than you need to use JS or jQuery to calculate the height using
$('#wrapperElement').css('margin-bottom', $('#footer').height());
Here, the selectors of #wrapperElement and #footer are my assumed ones, you can replace those with the your own selectors.
Something about fixed element - Horizontal Centering (I think it will be helpful to some users)
When you will make your element fixed, it will get out of the document flow, so if you are assigning fixed to the wrapper of footer element and want to center some content in there, than nest another element inside that wrapper and use width and margin: auto; for that...
Demo 2
HTML
<div></div>
<div>
<div>Reveal Me</div>
</div>
CSS
body > div:first-child {
height: 800px;
background: #eee;
margin-bottom: 200px;
z-index: 1;
position: relative;
}
body > div:last-child {
background: #aaa;
height: 200px;
position: fixed;
bottom: 0;
width: 100%;
}
body > div:last-child div {
width: 80%;
margin: auto;
outline: 1px solid red; /* To show that element is horizontally centered */
}
Note: Selectors used in this answer are too general and are good for
quick demonstration purposes, in real projects, make sure you use
specific selectors
After spending 16 hours and having sacrificed critters to various gods I must regretfully say that I'm on the verge of mental meltdown.
I am writing an PhoneGap 2.8 application for Android (in the future will port to iOS). As main frameworks I use jQuery (with many plugins), Require, Underscore and Backbone.
On one fatal morning I got a task that header menu of my application must "imitate" the way facebook app's header does (follow the scroll).
Initially I believed that adding "position:fixed" attribute to the header div would would be simple enough- have I never been more wrong. As it turns out, position:fixed css attribute doesn't work properly in WebView and the issue has endured for years now.
This issue has been discussed in length in various forums and articles and various "solutions" have been proposed- none are working in my case.
I have tried to set header's position to fixed when scrolling and to absolute when scrolling is done. Theoretically it works, but it is laggy.
Having tried that I looked into different plugins or frameworks that could help in the case.
iScroll - Forces a specified structure to html and severe lack of documentation threw me away from it.
jQueryMobile - Since it is a whole framework, integrating it to my project would mean changing alot of stuff. As I understand, it wont provide a persistent header.
I have heard of Bartender and GloveBox but neither of them have documentation and they aren't in constant development (last commits are > year old ).
Using jsHybugger I inspected the header when it is in position: fixed an I have noticed that Blue box that overlays a div being selected in inspector is staying where click area is for the header. So if I scroll, the header moves with viewport but hitarea stays in place. It got me wondering, if there is a way to force WebView to recalculate the click area?
All and any help is very much appreciated.
So, inspired by this link, I made a quick fiddle on how this could work without position:fixed. Note that the fiddle is not the same as the code here, it just illustrates how this is supposed to work.
HTML
<div class="page-wrapper">
<div class="header"><h3>header</h3></div>
<div class="content-wrapper">
<div class="content">
<!-- Your content goes here -->
</div>
</div>
</div>
CSS
body {
height: 100%;
padding: 0;
margin: 0;
}
.page-wrapper {
margin: 0;
padding: 0;
width: 100%;
height: 100%;
position: relative;
overflow: hidden;
}
.header {
position: absolute;
top:0;
left:0;
right:0;
padding: 3px 0;
color: #FFF;
background: #000;
text-align: center;
}
.content-wrapper {
position: absolute;
padding:0;
top: 65px;
left: 0;
right: 0;
bottom:0;
background: #CCC;
overflow-y: scroll;
-webkit-overflow-scrolling: touch;
}
.content {
padding: 15px;
}
Its not the problem of phonegap. Actually position: fixed doesnt work in android version lesser than 4.0
There is a quick css fix for it:
<div class="header"> this is fixed positioned div<div>
Css:
.header{ position:fixed ; -webkit-backface-visibility: hidden; top:0; left:0; width: 100px; height:30px; background: red; }
I came across after inheriting a project which was using the positioning system. Most people would probably know not to go down this road now but just in case someone does end up here looking for a solution...
It's possible to achieve the above with flexbox layouts.
In this way the css was as follows:
.pageWrapper {
margin: 0;
padding: 0;
width: 100%;
height: 100%;
overflow: hidden;
padding-top: env(safe-area-inset-top);
padding-bottom: env(safe-area-inset-bottom);
display: flex;
flex-direction: column;
}
.screen-content-wrapper {
padding:0;
flex: 1;
overflow-y: scroll;
-webkit-overflow-scrolling: touch;
}
I didn't edit my content css so only used the above to achieve what i was after.
Hopefully someone will find this helpful.