Footer doesn't stay in place (React-Gatsby) - javascript

Why my damn footer won't stay at the bottom of the page?
import React from "react"
import Navbar from "./navbar"
import Footer from "./footer"
import Sidebar from "./sidebar"
import "./layoutplus.css"
const Layout = ({ children }) => {
return (
<>
<Navbar />
<div className="main-cont">
<main id="main-post" className="main-post">{children}</main>
<Sidebar id="sidebar" className="sidebar"/>
</div>
<Footer />
</>
)
}
export default Layout
import React from 'react'
import {Link} from 'gatsby'
import {FaFacebook, FaTwitter, FaInstagram} from 'react-icons/fa'
export default function Footer() {
return (
<div id="footer" className="footer">
<div className="footer-middle">
<ul>
<li><Link className="footer-link" to="/">Home</Link></li>
<li><Link className="footer-link" to="/guides">Guides</Link></li>
<li><Link className="footer-link" to="/about">About</Link></li>
</ul>
<div className="footer-bottom">
<ul className="footer-ul">
<li><Link to="//" ><FaFacebook className="footer-dot" /></Link></li>
<li><Link to="//"><FaTwitter className="footer-dot" /></Link></li>
<li><Link to="//"><FaInstagram className="footer-dot"/></Link></li>
</ul>
<p>Build with <Link style={{ textDecoration: "none", color: "#663399" }} to="https://www.gatsbyjs.com/">Gatsby</Link>.</p>
<p>©{new Date().getFullYear()} <Link className="footer-link" to="/about">blablabla</Link> - All Rights Reserved</p>
</div>
</div>
</div>
)
}
/*MAIN CONT*/
.main-cont {
max-width: 1344px;
margin: 0 auto;
display: grid;
height: 100vh;
grid-template-columns: 4.5fr 1.5fr;
grid-template-rows: 1fr 1fr;
gap: 1rem;
grid-template-areas:
"main-post test-ads"
"main-post test-hottopic";
padding-top: 40px;
}
#media only screen and (max-width: 800px) {
.main-cont {
grid-template-columns: 1fr;
grid-template-rows: 2fr 1fr 1fr;
grid-template-areas:
"main-post"
"test-ads"
"test-hottopic";
padding-right: 10px;
padding-left: 10px;
}
}
.main-post {
grid-area: main-post;
}
.test-ads {
grid-area: test-ads;
border: 1px solid greenyellow;
text-align: center;
}
.test-hottopic {
grid-area: test-hottopic;
border: 1px solid red;
text-align: center;
}
/*FOOTER*/
.footer {
position: fixed;
bottom: 0;
width: 100%;
text-align: center;
background: var(--bgGray);
margin: 0;
padding-bottom: 20px;
}
.footer-middle {
color: var(--mainWithe);
}
.footer-middle ul {
list-style: none;
color: var(--mainWhite);
padding: 0rem 2px;
}
.footer-middle li {
font-size: 1.2rem;
display: inline;
margin-right: 1.5rem;
}
.footer-bottom {
padding-top: 0.5rem;
padding-bottom: 2rem;
}
.footer-link {
color: var(--offWhite);
text-decoration: none;
}
.footer-link:hover {
color: var(--mainOrange);
}
.footer-ul {
list-style: none;
display: inline;
}
.footer-dot {
color: var(--offWhite);
height: 27px;
width: 27px;
}
.footer-dot:hover {
transition: var(--mainTransition);
color: var(--mainOrange);
}
The footer seems to stay at the bottom of the screen always, but never at the end of the page. I don't know why, this problem starts when I added the grid to the .main-cont container, because I need a grid nested into the body.
Anyone has a solution?

With Gatsby, you should struck the brain a little bit, since it's not that easy to access the wrappers of the content, but of course, it doable.
Taking your <Layout> as an example:
import React from "react"
import Navbar from "./navbar"
import Footer from "./footer"
import Sidebar from "./sidebar"
import "./layoutplus.css"
const Layout = ({ children }) => {
return (
<>
<Navbar />
<div className="main-cont">
<main id="main-post" className="main-post">{children}</main>
<Sidebar id="sidebar" className="sidebar"/>
</div>
<Footer />
</>
)
}
export default Layout
Using the previous structure, you can't access the wrapper of your components because Gatsby wraps it between an unreachable <div> with an empty class. However, what you can do is to wrap it again within a known class element, such as:
const Layout = ({ children }) => {
return (
<section className="site-wrapper">
<Navbar />
<div className="main-cont">
<main id="main-post" className="main-post">{children}</main>
<Sidebar id="sidebar" className="sidebar"/>
</div>
<Footer />
</section>
)
}
Given that site-wrapper class you can add the following CSS:
.site-wrapper {
display: flex;
min-height: 100vh;
flex-direction: column;
}
main {
flex-grow: 1;
}
Basically, you are telling the wrapper (site-wrapper) to expand until filling the viewport (100vh). Since your main tag (change it to the desired class if needed) can grow free (flex-grow: 1) so your footer will be always at the bottom of the page because it's pushed by the rest of the flexbox column.
Flexbox has better acceptance/fallback within old browsers than grid has, but you can achieve it either way, the idea is always to push (or let the main grow) the footer at the bottom without depending on the content above, using some minmax should do the trick using a grid-based approach.

Related

Cannot scroll on React App even on page overflow

I am currently working on the Body portion for a Spotify clone using ReactJS. I am fairly new to Javascript, HTML, and CSS so apologies for any oversights.
I am having a problem where I cannot scroll down to the bottom of the playlists page even when there are more tracks to be shown. I have tried adding 'overflow-y: scroll' to my CSS which renders a scroll bar but even then, the page cannot be scrolled (see right scrollbar in screenshot below). I have included my Body.jsx below.
Screenshot of Spotify clone
Body.jsx
import React, { useEffect } from 'react'
import styled from 'styled-components';
import {AiFillClockCircle} from "react-icons/ai";
import axios from 'axios';
import { useStateProvider } from '../utils/StateProvider';
import { reducerCases } from "../utils/Constants";
export default function Body() {
const[ {token, selectedPlaylistId, selectedPlaylist} ,dispatch] = useStateProvider();
useEffect(() => {
const getInitialPlaylist = async () => {
const response = await axios.get(
`https://api.spotify.com/v1/playlists/${selectedPlaylistId}`, {
headers: {
Authorization: "Bearer " + token,
"Content-Type": "application/json",
},
}
);
const selectedPlaylist = {
id: response.data.id,
name: response.data.name,
description: response.data.description.startsWith("<a") ? "" : response.data.description,
image: response.data.images[0].url,
tracks: response.data.tracks.items.map(({track}) => ({
id: track.id,
name: track.name,
artists: track.artists.map((artist) => artist.name),
image: track.album.images[2].url,
duration: track.duration_ms,
album: track.album.name,
context_uri: track.album.uri,
track_number: track.track_number,
})),
};
dispatch({type: reducerCases.SET_PLAYLIST,selectedPlaylist});
};
getInitialPlaylist();
},[token,dispatch, selectedPlaylistId]);
return (
<Container>
{
selectedPlaylist && (
<>
<div className="playlist">
<div className="image">
<img src={selectedPlaylist.image} alt="selectedplaylist" />
</div>
<div className="details">
<span className="type">PLAYLIST</span>
<h1 className="title">{selectedPlaylist.name}</h1>
<p className="description">{selectedPlaylist.description}</p>
</div>
</div>
<div className="list">
<div className="header__row">
<div className="col">
<span>#</span>
</div>
<div className="col">
<span>TITLE</span>
</div>
<div className="col">
<span>ALBUM</span>
</div>
<div className="col">
<span><AiFillClockCircle /></span>
</div>
</div>
<div className="tracks">
{
selectedPlaylist.tracks.map(( {id,name,artists,image,duration,album,context_uri,track_number},index) => {
return (
<div className="row" key={id}>
<div className="col">
<span>{index+1}</span>
</div>
<div className="col detail">
<div className="image">
<img src={image} alt="track" />
</div>
<div className="info">
<span className="name">{name}</span>
<span>{artists}</span>
</div>
</div>
<div className="col">
<span>{album}</span>
</div>
<div className="col">
<span>{duration}</span>
</div>
</div>
);
})
}
</div>
</div>
</>
)
}
</Container>
);
}
//CSS for styled components
const Container = styled.div`
overflow-y: scroll; //scroll bar appears but doesn't scroll
.playlist {
margin: 0 2rem;
display: flex;
align-items: center;
gap: 2rem;
.image {
img {
height: 15rem;
box-shadow: rgba(0, 0, 0, 0.25) 0px 25px 50px -12px;
}
}
.details {
display: flex;
flex-direction: column;
gap: 1rem;
color: #e0dede;
.title {
color: white;
font-size: 4rem;
}
}
}
.list {
.header__row {
display: grid;
grid-template-columns: 0.3fr 3fr 2fr 0.1fr;
margin: 1rem 0 0 0;
color: #dddcdc;
position: sticky;
top: 15vh;
padding: 1rem 3rem;
transition: 0.3s ease-in-out;
}
.tracks {
margin: 0 2rem;
display: flex;
flex-direction: column;
margin-bottom: 5rem;
.row {
padding: 0.5rem 1rem;
display: grid;
grid-template-columns: 0.3fr 3.1fr 2fr 0.1fr;
&:hover {
background-color: rgba(0, 0, 0, 0.7);
}
.col {
display: flex;
align-items: center;
color: #dddcdc;
img {
height: 40px;
width: 40px;
}
}
.detail {
display: flex;
gap: 1rem;
.info {
display: flex;
flex-direction: column;
}
}
}
}
}
`;
If anyone has any ideas as to how I can get the page to be scrollable, I would greatly appreciate it. I have done lots of research but nothing has worked. Thank you so much!
I was working on the same project and faced the same issue.
I figured out that the issue lied in Spotify.jsx file.
Let this be the code:
.body {
height: 100%;
width: 100%;
overflow: auto;
&::-webkit-scrollbar {
width: 0.7rem;
max-height: 2rem;
&-thumb {
background-color:rgba(255, 255, 255, 0.6);
}
}
}

How to make content scrollable inside a flex box without given the height?

I'm trying to create a flex row split panel with a footer inside a column flexbox. However, I find out that I cannot make the content to be scrollable unless I limit the height of the container by coding height: calc(100% - FooterHeight). Does anyone know an alternative way to achieve this?
Thanks in advance!
Sandbox URL
My code:
import React from "react";
import "./styles.css";
const lefts = new Array(15).fill("Left");
const rights = new Array(15).fill("Right");
export default function App() {
return (
<div className="height">
<div className="column">
<div className="row">
<div className="row-left">
{lefts.map((left, index) => {
return (
<div key={index} className="item">
{left + index}
</div>
);
})}
</div>
<div className="row-right">
{rights.map((right, index) => {
return (
<div key={index} className="item">
{right + index}
</div>
);
})}
</div>
</div>
<div className="footer">Footer</div>
</div>
</div>
);
}
My CSS:
.height {
height: 600px;
width: 600px;
background-color: gray;
display: flex;
flex-direction: column;
}
.column {
flex: 1;
display: flex;
flex-direction: column;
height: 100%;
}
.row {
flex: 1;
display: flex;
height: calc(100% - 60px); // not preferred
}
.row-left {
width: 200px;
border: 1px solid red;
overflow: auto;
}
.row-right {
flex: 1;
border: 1px solid peru;
overflow: auto;
}
.item {
padding: 16px;
}
.footer {
flex-shrink: 0;
height: 60px;
border: 1px solid blue;
}
You need to replace that height with overflow: hidden for .row:
.row {
flex: 1;
display: flex;
overflow: hidden;
}
Here is fork of your Codesandbox:
https://codesandbox.io/s/fast-wood-1wxii

CSS Having two lists, sync their vertical scroll while allowing one to scroll horizontally

I have two lists where item i in list 1 is related to item i in list 2.
i want both lists to be scrollable vertically, so that items i always have the same scrolling position in both lists.
But list 2 has more content for a screen to display (like a timeline of sorts), so I want that list to be scrollable horizontally (Mind you not the item itself but the whole list), while list 1 stays fixed.
Is there any way to do this in CSS only?
This is what I have so far:
Codesandbox
Please note that this is just illustrating the point. The actual items are much bigger DOM structures and not just text.
I updated the codesandbox to illustrate the point.
I can't really seem to get the horizontal scrolling working. Any help would be much appreciated.
Set width to some appropriate large value (eg. 500px) and also set white-space: nowrap on the .rightPaneItem.
Keep in mind that value of the width property on the .rightPaneItem element will need to be adjusted according to the content of the rightPaneItem that has the longest content.
function App() {
return (
<div className="App">
<div className="leftPane">
LeftPane
{new Array(100).fill(0).map((_, i) => (
<div key={i} class="leftPaneItem">
item {i}
</div>
))}
</div>
<div className="rightPane">
RightPane
{new Array(100).fill(0).map((_, i) => (
<div key={i} class="rightPaneItem">
item {i} with a way longer text so you should be able to scroll
horizontally
</div>
))}
</div>
</div>
);
}
ReactDOM.render(<App />, document.getElementById("root"));
.App {
text-align: center;
max-height: 300px;
max-width: 300px;
display: flex;
border: 3px dashed green;
overflow: auto;
padding: 5px;
}
.leftPane {
display: flex;
flex-direction: column;
height: 100%;
flex: 1;
border: 2px solid red;
padding: 5px;
}
.rightPane {
display: flex;
flex-direction: column;
height: 100%;
flex: 2;
border: 2px solid blue;
padding: 5px;
overflow-x: auto;
}
.leftPaneItem {
height: 20px;
}
.rightPaneItem {
height: 20px;
width: 500px;
overflow-x: hidden;
white-space: nowrap;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.13.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.13.1/umd/react-dom.production.min.js"></script>
<div id="root"></div>
Edit:
Since you will have the content with variable length in the right column, you could use the following approach.
Instead of setting the width and overflow properties on .rightPaneItem, you could add overflow: auto on the outer container .App and .rightPane element.
function App() {
return (
<div className="App">
<div className="leftPane">
LeftPane
{new Array(100).fill(0).map((_, i) => (
<div key={i} class="leftPaneItem">
item {i}
</div>
))}
</div>
<div className="rightPane">
RightPane
{new Array(100).fill(0).map((_, i) => {
if (i % 2 == 0) {
return (
<div key={i} class="rightPaneItem">
item {i} with a way longer text so you should be able to scroll
horizontally
</div>);
} else {
return (
<div key={i} class="rightPaneItem">
item {i} with a way longer text so you should be able to scroll
horizontally. item {i} with a way longer text so you should be able to scroll
horizontally. item {i} with a way longer text so you should be able to scroll
horizontally
</div>);
}
})}
</div>
</div>
);
}
ReactDOM.render(<App />, document.getElementById("root"));
.App {
font-family: sans-serif;
text-align: center;
max-height: 300px;
max-width: 300px;
display: flex;
border: 3px dashed green;
overflow: auto;
padding: 5px;
}
.leftPane {
display: flex;
flex-direction: column;
height: 100%;
flex: 1;
border: 2px solid red;
padding: 5px;
}
.rightPane {
display: flex;
flex-direction: column;
height: 100%;
flex: 2;
border: 2px solid blue;
padding: 5px;
overflow: auto;
}
.leftPaneItem {
height: 20px;
}
.rightPaneItem {
height: 20px;
position: relative;
white-space: nowrap;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.13.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.13.1/umd/react-dom.production.min.js"></script>
<div id="root"></div>
I have also created a demo on codesandbox that is similar to the one posted in your question and uses the same CSS as the one used in second code snippet.

How do I set unique background images for react router components?

I'd like set to different background images for my 'Home' and 'About' components within the react project I'm building. I gave the 'Home' and 'About' components their own stylesheets (styles.css and about.css, respectively), then added a background-image: url() for each, but they both ended up with the 'Home' background.
Any suggestions on how to have different backgrounds for your components, when using react router?
Code as follows:
Home.jsx
import React from 'react'
import './styles.css'
import hashi_logo_2 from './Photos/hashi_logo_2.png'
import {Link} from 'react-router-dom'
function Home() {
return (
<div className = 'home'>
<nav className = 'nav'>
<ul>
<Link to = '/about' style={{ textDecoration: 'none' }} >
<li className='list'>About</li>
</Link>
<li className='list'>Food</li>
<li className='list'>Events</li>
<li className='list'>News</li>
<Link to ='/shop' style={{ textDecoration: 'none' }} >
<li className='list'>Shop</li>
</Link>
<li className='list'>Contact</li>
<li className='list'>Blog</li>
</ul>
</nav>
<main>
<div class='main__image'>
<img src= {hashi_logo_2}/>
</div>
</main>
</div>
)
}
export default Home
styles.css (styling for 'Home')
html * {
box-sizing: border-box;
font-family: 'Permanent Marker', cursive;
}
body {
margin: 0;
padding:0;
background-image: url('./Photos/hashi_pic_blurred_2.jpg');
background-repeat: no-repeat;
background-size: cover;
backdrop-filter: brightness(100%);
}
/* Navigation */
.nav {
background-color:#8b0000;
margin:0;
padding: 15px 0;
opacity: 0.75;
position: fixed;
width:100%;
}
ul {
display:flex;
list-style: none;
flex-direction: row;
justify-content: space-around;
font-size: 20px;
}
.list {
list-style: none;
text-decoration: none;
color: white;
font-size: 25px;
}
.list:hover{
background-color: black;
}
/* Logo */
main {
text-align: center;
padding-top: 130px;
padding-top:180px;
}
img {
max-width: 40%;
height: auto;
}
About.jsx
import React from 'react'
import './about.css'
function About() {
return(
<div className = 'about'>
<p>
Hashigo Zake takes the provision of fine beer to new levels.
<br/>
<br/>
Seven days a week, 362 days a year, we serve the best that New Zealand's booming craft brewing industry has to offer.
We are also building the best range of imported beer that New Zealand has seen.
<br/>
We deal directly with breweries in Australia, Japan and the US and import many of the best beers in the Pacific rim.
<br/>
We also have access to some of the best beers coming from Europe.
<br/>
<br/>
We open at midday every day.
<br/>
Our location is 25 Taranaki St, Te Aro, Wellington, New Zealand.
</p>
<h2>"And he dreamed, and behold a ladder set up on the earth, and the top of it reached to heaven."</h2>
</div>
)
}
export default About
about.css
.about {
height:100%;
background-image: url('./Photos/hashi_taps.jpg');
}
p {
margin-top: 50px;
color: white;
text-align: center;
font-size: 30px;
/* background-color: rgb(139,0,0, 0.75); */
font-family: 'Open Sans', sans-serif;
padding-left: 50px;
padding-right: 20px;
transform: translateY(20%);
font-weight: bold;
}
h2 {
color: white;
text-align: center;
font-size: 40px;
padding-left: 20px;
padding-right: 20px;
margin-top: 400px;
transform: translateY(-450%);
}
import React from 'react';
import Home from './Home'
import About from './About'
import Shop from './Shop'
import {BrowserRouter as Router, Switch, Route} from 'react-router-dom'
function App() {
return (
<Router>
<div>
<Switch>
<Route path ='/' exact component = {Home}/>
<Route path = '/about' component = {About}/>
<Route path = '/shop' component = {Shop}/>
</Switch>
</div>
</Router>
)
}
export default App;

Match the unspecified height of an img with another adjacent div?

This is the JSX of the component in question:
import React from 'react'
import * as classes from './PhotoCard.module.scss'
const PhotoCard = ({ img, name, username, profileImg, style }) =>
<div className={classes.PhotoCardWrapper} style={style}>
<div className={classes.ImgWrapper}>
{img}
</div>
<div className={classes.Sidebar}>
<div className={classes.Creator}>
<div className={classes.ProfilePicture}>
{profileImg}
</div>
<div className={classes.ProfileInfo}>
<h5>{name}</h5>
<p>{username}</p>
</div>
</div>
<div className={classes.Comments}>
<input type="text" name="comment" id="comment" placeholder="Write a comment" />
</div>
</div>
</div>
export default PhotoCard
Here is the relevant SCSS:
.PhotoCardWrapper {
width: 100%;
display: flex;
justify-content: flex-start;
align-items: flex-start;
box-sizing: border-box;
border-radius: 5px;
box-shadow: 0 2px 6px rgba(0,0,0,0.16), 0 2px 6px rgba(0,0,0,0.2);
.ImgWrapper {
display: flex;
width: 100%;
img {
width: 100%;
border-top-left-radius: 5px;
border-bottom-left-radius: 5px;
}
}
.Sidebar {
width: 300px;
height: 100%;
display: flex;
flex-flow: column nowrap;
.Creator {
width: 100%;
display: flex;
padding: 10px;
overflow: hidden;
overflow-x: auto;
box-sizing: border-box;
.ProfilePicture {
width: 40px;
height: 40px;
border-radius: 40px;
background-image: url('../../static/defaults/placeholder.png');
background-size: contain;
cursor: pointer;
margin-right: 10px;
flex-shrink: 0;
img {
width: 100%;
height: 100%;
border-radius: 40px;
}
}
.ProfileInfo {
height: 40px;
display: flex;
flex-flow: column nowrap;
justify-content: center;
}
h5 {
font-weight: 500;
letter-spacing: 0.5px;
}
p {
font-size: 0.7em;
color: $color-2;
}
}
.Comments {
width: 100%;
display: flex;
flex-flow: column nowrap;
flex-grow: 1;
background: #525252;
input {
border: none;
border-top: 1px solid $color-1;
font-size: 0.9em;
padding: 5px;
}
}
}
}
To explain, I'm trying to preserve the aspect ratio of the image on the left side of the component. I can use an absolute unit for the width however I cannot use an absolute height unit as the height of the component will be based upon the aspect ratio of the image.
The "Sidebar" using flexbox will therefore have to match the height of whatever the unspecified height of the image ends up being. I cannot figure out a solution for this. As you can see I'm trying to use flex-grow on the Comments div which will not work without specifying height in parent elements.
This is the solution I found to this:
import React, { useEffect, useState } from 'react'
import * as classes from './_PhotoCard.module.scss'
import PropTypes from 'prop-types'
const PhotoCard = ({ ident, img, name, profileImg }) => {
const [height, setHeight] = useState(null)
const [imgClicked, setImgClicked] = useState(null)
useEffect(() => setHeight(document.getElementsByClassName('_PhotoCard_ImgWrapper__3S6GQ').item(ident).clientHeight), [ident])
const creatorJSX = (
<>
<div className={classes.ProfilePicture}>
{profileImg}
</div>
<div className={classes.ProfileInfo}>
<h5>{name}</h5>
</div>
</>
)
const imgClickedHandler = () => {
if (imgClicked === null) {
setImgClicked(classes.imgClicked)
document.body.style.overflow = "hidden"
} else {
setImgClicked(null)
document.body.style = "none"
}
}
return (
<div className={`${classes.PhotoCardWrapper} ${imgClicked}`} style={window.matchMedia("(min-width: 600px)").matches ? { marginBottom: 40 } : { marginBottom: 20 }}>
<div className={classes.CreatorMobile}>
{creatorJSX}
</div>
<div className={classes.ImgWrapper} onClick={() => imgClickedHandler()}>
{img}
</div>
<div className={classes.Sidebar} style={window.matchMedia("(min-width: 600px)").matches ? { height: height } : null}>
<div className={classes.SidebarTop}>
<div className={classes.Creator}>
{creatorJSX}
</div>
<div className={classes.Comments}/>
</div>
<input type="text" name="comment" id="comment" placeholder="Write a comment" />
</div>
</div>
)
}
PhotoCard.propTypes = {
ident: PropTypes.number,
img: PropTypes.element,
name: PropTypes.string,
profileImg: PropTypes.element,
}
export default PhotoCard
This could only be achieved by implementing some JS witchcraft.

Categories

Resources