How to display a fixed navbar in Nextjs? - css

I have a Nextjs app that displays the same navbar on each page. The navbar has a fixed position. The display is correct on the homepage (written in index.tsx). But when I click on a new page, the new page is hidden behind the navbar!
The issue disappears if I remove the fixed position property. But I can't believe Nextjs doesn't support such a basic task.
The code is very simple:
// _app.tsx
function MyApp({ Component, pageProps }: AppProps) {
return (
<>
<Navbar />
<Component {...pageProps} />
</>
);
}
export default MyApp;
// about.tsx
const About: NextPage = () => {
return (
<section>
<h1>About</h1>
</section>
);
};
export default About
// navbar.tsx
export default function Navbar() {
const router = useRouter();
return (
<nav className={styles.navbar}>
<Link href="/">
<Image
src={icon.src}
className={styles.logo}
alt="logo"
width={70}
height={70}
/>
</Link>
<ul className={styles.list}>
<li
className={
router.route === "/about" ? styles.listItemActive : styles.listItem
}
>
<Link href="/about">About</Link>
</li>
</ul>
</nav>
);
}
//navbar.module.css
.navbar {
background-color: var(--dark);
color: #fff;
height: 80px;
width: 100vw;
display: flex;
justify-content: space-between;
align-items: center;
padding: 12px;
position: fixed;
z-index: 999;
}
.logo {
cursor: pointer;
}
.list {
list-style: none;
padding: 0;
margin: 0;
display: flex;
align-items: center;
}
.listItem {
cursor: pointer;
}
.listItemActive {
cursor: pointer;
color: var(--red);
}
How to fix this?

Just add a position to your css.
top: 0px;
right: 0px;
left: 0px;
https://developer.mozilla.org/docs/Web/CSS/position

If what you want is to have a sticky navbar, you can do it with pure CSS with position: sticky like this:
header, nav, main {
padding: 1.7rem 1rem;
}
header {
background-color: #d99;
}
nav {
position: sticky;
top: 2rem;
background-color: #9d9;
}
main {
height: 100vh;
background-color: #99d;
}
--
<header>
Header
</header>
<nav>
Navbar
</nav>
<main>
Main
</main>

position: sticky;
top: 0px;
right: 0px;
left: 0px;
this worked for me!

Related

Custom style on navbar when a section is active on the same page in Gatsby

I am trying to create a simple landing page with React. As per the title I have tried to get the active section heading (in the navbar) to be highlighted (change color) when the user scrolls to that section on the page, no success so far even after searching online for a long time. Really stuck. Following the tutorial, I am using styled-components for styling, different files for each component. Here is the code for my Navbar:
import React, { useState, useEffect } from 'react'
import styled from 'styled-components'
import { FaBars, FaTimes } from 'react-icons/fa'
import { IconContext } from 'react-icons/lib'
import { Link } from 'gatsby'
import Icon from '../images/Icon.png'
import { ButtonOne } from './Button'
import ScrollSpy from 'react-scrollspy-navigation';
import './layout.css'
const Navbar = () => {
const [click, setClick] = useState(false)
const [scroll, setScroll] = useState(false)
const handleClick = () => setClick(!click)
const changeNav = () => {
if (window.scrollY >= 130){
setScroll(true)
} else {
setScroll(false)
}
}
useEffect(() => {
changeNav()
window.addEventListener('scroll', changeNav)
}, [])
return (
<>
<IconContext.Provider value={{ color: '#fabf49'}}>
<Nav active={scroll} click={click}>
<NavbarContainer>
<NavLogo to='/'>
<NavIcon>
<img src={Icon} height={100} width={100} alt='Icon' />
</NavIcon>
</NavLogo>
<MobileIcon onClick={handleClick}>{click ? <FaTimes /> : <FaBars />}</MobileIcon>
<NavMenu onClick={handleClick} click={click}>
<ScrollSpy offsetTop={80} duration={1500}>
<a href='/#s1' ref={React.createRef()}>
<NavItem>
<NavLinks to='/#s1' activeClassName={`active`}>Company</NavLinks>
</NavItem>
</a>
<a href='#s4' ref={React.createRef()}>
<NavItem>
<NavLinks to='/#s4' activeClassName={`active`}>Features</NavLinks>
</NavItem>
</a>
<a href='#s7' ref={React.createRef()}>
<NavItem>
<NavLinks to='/#s7' activeClassName={`active`} >Partners</NavLinks>
</NavItem>
</a>
<a href='#s6' ref={React.createRef()}>
<NavItem>
<NavLinks to='/#s6' activeClassName={`active`}>Updates</NavLinks>
</NavItem>
</a>
<a href='#s8' ref={React.createRef()}>
<NavItem>
<NavLinks to='/#s8' activeClassName={`active`}>Careers</NavLinks>
</NavItem>
</a>
<a href='#s8' ref={React.createRef()}>
<NavItem>
<NavLinks to='/#s8' activeClassName={`active`}>Contact Us</NavLinks>
</NavItem>
</a>
<NavBtn>
<ButtonOne a href='#s8' ref={React.createRef()} style={{scrollBehavior: "smooth"}}>BOOK NOW</ButtonOne>
</NavBtn>
</ScrollSpy>
</NavMenu>
</NavbarContainer>
</Nav>
</IconContext.Provider>
</>
)
}
export default Navbar
const Nav = styled.div`
background: ${({ active }) => (active ? '#1b2227' : 'transparent')};
height: 80px;
display: flex;
justify-content: center;
align-items: center;
font-size: 1rem;
position: sticky;
top: 0;
z-index: 999;
#media screen and (max-width: 1120px) {
background: ${({ click }) => (click ? '#1b2227' : 'transparent')};
transition: 0.8s all ease;
position: sticky;
background: ${({ active }) => (active ? '#1b2227' : 'transparent')};
height: 80px;
display: flex;
justify-content: center;
align-items: center;
font-size: 1rem;
position: sticky;
top: 0;
z-index: 999;
}
`
const NavbarContainer = styled.div`
display: flex;
justify-content: space-between;
height: 80px;
z-index: 1;
width: 100%;
`
const NavLogo = styled(Link)`
color: white;
justify-content: flex-start;
cursor: pointer;
text-decoration: none;
font-size: 1.5rem;
display: flex;
align-items: center;
margin-left: 2.5rem;
`
const NavIcon = styled.div`
margin: 0 0.5rem 0 2rem;
`
const MobileIcon = styled.div`
display: none;
#media screen and (max-width: 1120px) {
display: block;
position: absolute;
top: 0;
right: 0;
transform: translate(-100%, 60%);
font-size: 1.8rem;
cursor: pointer;
}
`
const NavMenu = styled.ul`
display: flex;
align-items: center;
list-style: none;
text-align: center;
#media screen and (max-width: 1120px) {
display: flex;
flex-direction: column;
width: 100%;
height: 90vh;
position: absolute;
top: ${({ click }) => (click ? '100%' : '-1000px')};
opacity: 1;
transition: all 0.2s ease;
background: #1b2227;
color: #fabf49;
}
`
const NavLinks = styled(Link)`
color: #fff;
display: flex;
align-items: center;
text-decoration: none;
padding: 0.5rem 1rem;
height: 100%;
&:hover {
color: #fabf49;
}
#media screen and (max-width: 1120px) {
text-align: center;
padding: 2rem;
width: 100%;
display: table;
color: #fabf49;
&:hover {
color: white;
transition: all 0.3s ease;
}
}
`
const NavItem = styled.li`
height: 80px;
margin-right: 2rem;
#media screen and (max-width: 1120px) {
width: 100%;
}
`
const NavBtn = styled.div`
display: flex;
align-items: center;
margin-right: 3rem;
#media screen and (max-width: 1120px) {
display: none;
}
`
and here is my index page where all the different sections are assembled into the landing page:
import * as React from "react"
import Layout from "../components/layout"
import Seo from "../components/seo"
import Hero from "../components/Hero"
import SectionTwo from "../components/SectionTwo"
import SectionThree from "../components/SectionThree"
import SectionFour from "../components/SectionFour"
import SectionFive from "../components/SectionFive"
import SectionSix from "../components/SectionSix"
import Partners from "../components/Partners"
const IndexPage = () => (
<Layout>
<Seo title="CARNIVAL" />
<section id='s1'><Hero /></section>
<section id='s2'><SectionTwo /></section>
<section id='s3'><SectionThree /></section>
<section id='s4'><SectionFour /></section>
<section id='s5'><SectionFive /></section>
<section id='s6'><SectionSix /></section>
<section id='s7'><Partners /></section>
</Layout>
)
export default IndexPage
For additional info here is the Layout component:
import * as React from "react"
import Footer from "./Footer"
import { GlobaStyle } from "./GlobalStyles"
import Navbar from "./Navbar"
const Layout = ({ children }) => {
return (
<>
<GlobaStyle />
<Navbar />
<main>{children}</main>
<section id='s8'><Footer /></section>
</>
)
}
export default Layout
and the css file (many related answers have a css file so I tried that too):
.active{
color: #fabf49;
}
I have managed to get the scrollspy working, however I am stuck on the active part being highlighted/custom styled in the navbar.

Unable to center block element horizontally

I am unable to center elements that will be a list of blog posts going forward. The Postlist element is loaded into my App.js file. I was able to center the nav bar using the technique mentioned here under the Horizontally section and under the subsection titled Is there more than one block level element? but when I attempt to do the same technique on the list of blog posts, it doesn't work, bear in mind that the list of blog posts will be dynamic in the future.
PostList.css file:
.blog-list-container {
display: block;
text-align: center;
margin: 0 auto;
}
.blog-element {
display: block;
width: 50%;
padding-top: 60px;
padding-bottom: 60px;
padding-right: 30px;
padding-left: 30px;
}
And Postlist.js file:
import React from 'react';
import App from '../../App';
import './PostList.css';
import {
BrowserRouter as Router,
Routes,
Route,
Link,
Outlet,
useParams
} from 'react-router-dom';
const PostList = ( props ) => (
<div className="blog-list-container">
<Router>
<Link to={'/posts/${}'} className="blog-element">element 1</Link>
<Link to={'/posts/${}'} className="blog-element">element 2</Link>
<Link to={'/posts/${}'} className="blog-element">element 3</Link>
</Router>
</div>
);
export default PostList
There is a cleaner, shorthand alternative to some of the suggested:
.blog-element {
display: block;
width: 50%;
padding: 60px 30px;
margin: 0 auto;
}
but I would advise using flexbox though:
While looking at your code and what is mentioned you should consider D.R.Y. when writing components, example:
const PostList = (props) => (
<div className='blog-list-container'>
<Router>
{posts.map((post) => {
return (
<Link key={post.id} to={post.link} className='blog-element'>
{post.name}
</Link>
)
})}
</Router>
</div>
)
export default PostList
It is behaving exactly as you have set the css rules.
.blog-element {
display: block;
width: 50%;
padding-top: 60px;
padding-bottom: 60px;
padding-right: 30px;
padding-left: 30px;
margin: 0 auto; // will center it to your blog list container.
}
Although i would suggest that you set the max-width to the container and remove the width from blog element.
.blog-list-container {
text-align: center;
}
.blog-element {
display: block;
width: 50%;
padding: 60px 30px;
margin: 0 auto; // new line
}
Add this line only in your code
or Code like this
.blog-list-container {
text-align: center;
}
.blog-element {
display: block;
padding: 60px 30px;
}

How to fit React Modal size children?

I am trying to load a dynamic login page with React Modal. Is there a way to make React Modal resize to the size of its child elements?
//App.js
import "./styles/app.scss";
import Layout from './options/Layout'
import Login from './Components/Login'
import { useState } from "react";
import Modal from 'react-modal'
function App() {
const [OpenModal, setOpenModal] = useState(false)
return (
<div id="app" className="App">
<Layout>
<button onClick = {() => setOpenModal(true)}>open modal</button>
<Modal isOpen = {OpenModal}>
<Login/>
</Modal>
</Layout>
</div>
);
}
export default App;
//login.scss
.login {
display: flex;
justify-content: center;
align-items: center;
width: 300px;
height: 280px;
margin: 0 auto;
background-color: #5c8fc2;
border-radius: 30px;
}
.login_top {
display: flex;
align-items: center;
justify-content: center;
margin-top: -40px;
margin-bottom: 20px;
color: whitesmoke;
}
.login_register_container {
border: none;
outline: none;
border-radius: 50%;
}
button {
margin-right: 12px;
margin-top: 30px;
border: none;
border-radius: 4px;
cursor: pointer;
}
I want to dynamically manage the size according to the child element.
I've tried several methods, but without success. How to fit modal's component to child element???
If you use the developer tools you can see that the content grows because they have applied some styles to the modal.
position: absolute;
inset:40
inset is same as
top: 40px;
left: 40px;
right: 40px;
bottom: 40px;
If you want your content to be exactly the same size as your content, you can remove the right and bottom from the styles.
<ReactModal
isOpen={true}
contentLabel="Minimal Modal Example"
className="Modal"
>
<div>
<div style={{ height: '500px' }}>Some content</div>
</div>
<button onClick={() => {}}>Close Modal</button>
</ReactModal>
CSS:
.Modal {
position: absolute;
top: 40px;
left: 40px;
background-color: papayawhip;
}
You will lose equal spacing on all sides of the modal if you do this though.
Here is an example. https://stackblitz.com/edit/react-vxe3cn

My Link in react won't work when clicked on

When i click on the links, they wont work. But when I change the position in ul.pullRight li:before to relative, the styling disappears and the link works. There's a hover effect in the links.
This is my NavBar component
import React from 'react'
import PropTypes from 'prop-types'
import { Link } from 'react-router-dom'
const Navbar = ({ icon, title }) => {
return (
<nav className='navbar bg-primary'>
<h1 style={{ fontWeight: 'bold', fontSize: '35px', color: 'whitesmoke'}}><i className={icon}></i>{title}</h1>
<ul className='container pullRight'>
{/* LINK to is used in place of <a> tag */}
<li><Link to="/">Home</Link></li>
<li><Link to="/about">About</Link></li>
<li><Link to="/login">Login</Link></li>
<li><Link to="/logout">LogOut</Link></li>
</ul>
</nav>
)
}
This is the css file
/* Pull right */
ul.container li
{
color: #FFF;
text-decoration: none;
font: 15px Raleway;
margin: 0px 10px;
padding: 10px 10px;
position: relative;
z-index: 0;
cursor: pointer;
}
ul.pullRight li:before
{
position: absolute;
width: 2px;
height: 100%;
left: 0px;
top: 0px;
content: '';
background: #FFF;
opacity: 0.3;
transition: all 0.3s;
}
ul.pullRight li:hover:before
{
width: 100%;
}
here i'm assuming that you don't want to li:before to be clicked so you can add this to the css, pointer-events: none and it won't cover the initial element anymore.
i did not test this, but please do test and tell if it worked.

changing CSS of element on page scroll

I have a fixed header component as the two pics below illustrate. The current styling that I have is fine for when the page loads and nothing has changed. However, I want the header to have a visible border-bottom of say 1px solid black as soon as the user starts to scroll down the page. So in this case, this styling change would apply to the second pic. How can I accomplish this?
header on page load:
header on scroll:
Header.js:
const Header = props => {
return (
<header className="header-container">
<div className="logo-container">
<img className="white-logo" src={logo} alt="Food Truck TrackR logo white" />
</div>
<section className="header-section-one">
<div className="location-sub-div">
<i class="fas fa-map-marker-alt"></i>
<h3>User Location</h3>
</div>
<div className="order-sub-div">
<i class="fas fa-store"></i>
<h3>Order now</h3>
</div>
</section>
<section className="header-section-two">
<NavLink to="/dine/search" className="search-sub-div">
<i class="fas fa-search search-icon"></i>
<h3>Search</h3>
</NavLink>
<div className="acct-sub-div">
<i class="fas fa-user acct-icon"></i>
<h3>Account</h3>
</div>
</section>
</header>
)
}
Header.scss:
.header-container {
width: 100%;
height: 9vh;
display: flex;
align-items: center;
color: black;
background: white;
font-size: 0.6rem;
padding-left: 4%;
padding-right: 4%;
position: fixed;
top: 0;
// border-bottom: 1px solid black;
z-index: 99;
}
.logo-container {
width: 20%;
margin-right: 6%;
.white-logo {
width: 100%;
}
}
.header-section-one {
width: 32%;
display: flex;
margin-right: 25%;
justify-content: space-evenly;
.location-sub-div {
display: flex;
h3 {
width: 100%;
white-space: nowrap;
}
}
.order-sub-div {
display: flex;
h3 {
white-space: nowrap;
}
}
}
.header-section-two {
width: 32%;
display: flex;
justify-content: space-evenly;
.search-sub-div {
display: flex;
.search-icon {
margin-right: 1%;
}
}
.acct-sub-div {
display: flex;
.acct-icon {
margin-right: 1%;
}
}
}
i {
margin-right: 1% !important;
}
This neat CSS trick might help you with the problem:
html:not([data-scroll='0']) {
.header-container {
width: 100%;
height: 9vh;
display: flex;
align-items: center;
color: black;
background: white;
font-size: 0.6rem;
padding-left: 4%;
padding-right: 4%;
position: fixed;
top: 0;
border-bottom: 1px solid black;
z-index: 99;
}
}
Here is a, link further explaining the solution: https://css-tricks.com/styling-based-on-scroll-position/
Good luck.
You can add an event listener to the document, and when a scroll event is fired, you can check to see what the vertical scroll position (scrollTop) of the document is, and conditionally show a border based on that value.
Here's an example:
import React, { useEffect, useState } from "react";
const Header = () => {
// Store a bool that determines if the border is visible
const [isBorderVisible, setIsBorderVisible] = useState(false);
useEffect(() => {
// Define a function that is called when the scroll event fires
const handleScroll = e => {
const scrollTop = e.target.documentElement.scrollTop;
if (scrollTop > 200) {
setIsBorderVisible(true);
} else {
setIsBorderVisible(false);
}
};
// Add the event listener inside a useEffect
if (document) {
document.addEventListener("scroll", handleScroll);
}
// Remove the event listener on unmount
return () => {
if (document) {
document.removeEventListener("scroll", handleScroll);
}
};
}, [setIsBorderVisible]);
return (
<div
style={{
position: "fixed",
top: 0,
left: 0,
right: 0,
height: "100px",
background: "hotpink",
// Conditionally style the border
borderBottom: isBorderVisible ? "2px solid #000" : "0"
}}
/>
);
};
So we have a useEffect, that adds an event listener to the document, listening for the scroll event. Whenever a scroll occurs, the handleScroll function (also defined inside the useEffect) fires.
In this function, we get the scrollTop value, which is the number of pixels that have been scrolled from the top of the document.
In the example, we are setting the state value isBorderVisible to true once we have a scrollTop greater than 200 pixels, but this can be anything you want.
In the header's style, we conditionally set a border, based on the state value of isBorderVisible.

Resources