Have a "sticky" button right underneath another "sticky" navbar - css

I have an app file which contains my own custom appbar and different page components:
const styles = theme => ({
appBar: {
width:'100%',
},
});
class App extends Component {
render() {
const {classes} = this.props;
return (
<React.Fragment>
<CssBaseline />
<AppBar position="sticky" className={classes.appBar} />
<Page1 show={someCondition} />
<Page2 show={someCondition} />
.
.
<Page99 show={someCondition} />
</React.Fragment>
);
}
}
The Appbar is sticky so it always shows on the top.
Each page component has a button which is always on the top of that page:
const styles = theme => ({
button: {
width:'100%',
},
});
class Page99 extends Component {
render() {
const {classes} = this.props;
return (
<React.Fragment>
<div>
<Button variant="contained" className= {classes.button}>
Action Button
</Button>
</div>
{/* Some other stuff */>
</React.Fragment>
);
}
}
I know want this button to always be right under the appbar. So when the user scrolls down this button should remain sticky just like the appbar does. I tried to set the positioning to sticky hoping it would stack underneath it but it wouldn't. The appbar is dynamic so I don't know the exact height it will be since on different resolutions it will look different so I couldn't use something like fixed positioning.

You can set position of page container as relative and set button as absolute.
the you can align it to top right of the page or wherever you want.
Check this fiddle is this is what you need
.componentparent {
position: relative;
height:100px;
max-height: 50px;
overflow: auto;
}
.button {
position: fixed;
top: 30px;
}
.otherelements{
top: 70px;
position: relative;
}
<div id="parent-container">
<div> your app bar </div>
<div class='componentparent'>
<button class='button'>my button</button>
<div class='otherelements'>your component</div>
</div>
</div>

Place your button inside your appbar and set your button to position to absolute and add top: 100% to move it exactly at the bottom of appbar.

Related

Material UI Button Hover Not Working Absolute Position

I have a div with a button and another div in it. The button is normally hidden and the inner div has a bunch of graphs and text. In certain circumstances, I want to blur the inner div and have the button float on top in the middle of the blurred out section, kind of like you see on medium or news sites when asking for subscriptions (although I removed the logic for the example). The way I'm doing it is using absolute positioning for the button, but when I do that, all of the hover functionality just flat out isn't working on the button. It doesn't change the background color of the button or change the cursorI'm using material UI and react. Here is a code sample ->
const useStyles = makeStyles((theme) => ({
blur: {
filter: "blur(7px)",
},
relativePos: {
position: "relative",
},
absolutePos: {
position: "absolute",
top: "50%",
left: "50%",
},
floatingBtn: {
"&:hover": {
cursor: "pointer",
backgroundColor: "red",
},
},
});
// some other stuff
<div className={classes.relativePos}>
<Button
variant="contained"
color="primary"
className={`${classes.absolutePos} ${classes.floatingBtn}`}
>
Button Text
</Button>
<div className={classes.blur}>
{/* Blurred Inner Div Stuff */}
</div>
</div>
I'd love suggestions on either 1) how to get this implementation working OR 2) a better implementation NOT using absolute positioning, if there's a better, more modern approach.
There are two solutions:
use zIndex on the button that is greater than the blurred inner div
Move the button under your blurred inner div
I would prefer the 2nd approach as you don't need to know the zIndex of other elements
const useStyles = makeStyles((theme) => ({
blur: {
filter: "blur(7px)"
},
relativePos: {
position: "relative"
},
absolutePos: {
position: "absolute",
top: "50%",
left: "50%"
// zIndex: 1000 <- Add The zIndex here if you want 1st approach
},
floatingBtn: {
"&:hover": {
cursor: "pointer",
backgroundColor: "red"
}
},
// This is temp button to just toggle the absolute button
tempButton: { margin: "30px 0" }
}));
export default function App() {
const classes = useStyles();
const [showButton, setShowButton] = useState(false);
return (
<div className={classes.relativePos}>
{/* Your graphs area */}
<div className={classes.blur}>This is graphs area</div>
{/* Your absolute button with hover effect */}
{/* you can add it at the bottom and then no need to use zIndex */}
{showButton && (
<button className={`${classes.absolutePos} ${classes.floatingBtn}`}>
Button
</button>
)}
{/* Temp button to show/hide the absolute button, you should have ur own logic */}
<button
className={classes.tempButton}
onClick={() => setShowButton(!showButton)}
>
Click me to show/Hide the button
</button>
</div>
);
}
working example: codesandbox
BTW If you remove filter: "blur(7px)" from the blur class then the hover should work without changing anything in your code. I have no idea why (-_-)

Hiding Element in React Based on SCSS/CSS

I have a global element that needs to be hidden only on a specific page.
The problem I encounter is that when I try to hide the element on a specific page base on importing the css, it also hides on all pages. It needs to hide only on this page. The <Main /> page is where my main pages are located like the /products
<body>
<Main />
<div style={{ height: 800, position: "absolute" }} className="products">
Hide this on none /products page
</div>
</body>
products.scss
body {
.products {
display: none;
}
}
Product
import { useRouter } from 'next/router'
const Products = () => {
const router = useRouter()
if (router.pathname === '/products') {
require('../styles/products.scss')
}
}
<div style={{ height: 800, position: "absolute" }} className={router.pathname === '/products' ? 'hidden' : ''}>
Hide this on none /products page
</div>
and now set display: none; for the hidden class. :)

Print MaterialUI Dialog fullscreen

I am new to React and Material-UI and I want to print my current dialog.
The problem is that I cannot find a way to maximize my Dialog for priting (set to fullScreen) without doing it in the Browser, too. So I basically want a smaller Dialog in my Browser and for the Dialog the maximal size.
Here is my basic code in TSX:
import React, { Component} from 'react';
import { Button, Dialog } from '#material/core';
export default class MUITester extends Component {
render(){
return (
<Dialog fullScreen={false}>
<div>
<Button onClick={() => window.print()}>
PRINT
</Button>
</div>
</Dialog>
);
}
And the corresponding css file:
#media print {
.print {
fullScreen=true;
color: blue;
}
}
Can I solve it using css? Or do I have to use React/Material-UI?
I solved it! Change the classes of Dialog:
<Dialog classes={{paperFullScreen: "prePrint printDialog"}} fullScreen>
Here my css:
.prePrint {
height: auto !important;
max-width: 600px !important;
}
/*Print Dialog*/
#media print {
.printDialog {
max-width: 100% !important;
}
}
You can set the width of your dialog like this:
<Dialog fullWidth={true} maxWidth='md'>
<div>
<Button onClick={() => window.print()}>
PRINT
</Button>
</div>
</Dialog>
As given in the Documentation
For printing div, which is inside dialog, use below code, and add css also
import React, { Component} from 'react';
import { Button, Dialog } from '#material/core';
export default class MUITester extends Component {
render(){
return (
<Dialog classes={{paperFullScreen: "prePrint"}} fullScreen>
<div id="DialogPrint">
some text some text , some paragraph and so on
</div>
<div >
<Button onClick={() => window.print()}>
PRINT
</Button>
</div>
</Dialog>
);
}
}
add below code in css
.prePrint {
height: auto !important;
max-width: 600px !important;
}
/*Print Dialog*/
#media print {
body * {
visibility: hidden;
}
#DialogPrint,
#DialogPrint * {
visibility: visible;
}
#DialogPrint {
position: absolute;
left: 0;
top: 0;
}
}
I was looking for a full-screen Dialog on mobile and a simple dialog for desktop and the below example resolved my issue, please take a look if helps.
import useMediaQuery from '#mui/material/useMediaQuery';
function MyComponent() {
const theme = useTheme();
const fullScreen = useMediaQuery(theme.breakpoints.down('md'));
return <Dialog fullScreen={fullScreen} />;
}
You can check demo on MUI official documentation.
You just need to add fullScreen flag to modal component in order to achieve full screen.
Like below
<Dialog fullScreen open={open} onClose={handleClose} TransitionComponent={Transition}>
And if you don't want to use fullScreen, simply remove that fullScreen flag and don't need to use CSS here.

React Router how to setup transition on parent element

I have a simple router configuration:
<Router history={browserHistory}>
<Route lang="en" path="en" component={App}>
<Route path="*" component={PageFactory} />
</Route>
<Redirect from="*" to="/en/*" />
</Router>
and main App component has the following:
<div className="app">
<Home />
<Sidebar {...sidebarProps}>
{this.props.children}
</Sidebar>
</div>
So, the Home component always opens when you open the react application. When I click a link in Home component (e.g /en/pages/about-page), the contents of the page gets loaded to Sidebar component and Sidebar gets a prop isOpen (That's what ...sidebarProps is for). Everything works fine. When I click a link Sidebar opens, and contents show with overlay etc. However, transitions do not animate. Here is my CSS:
.sidebar {
position: fixed;
left: 0px;
top: 0px;
width: 100%;
height: 100%;
z-index: 200;
visibility: hidden;
background: rgba(0, 0, 0, 0.8);
overflow: scroll;
#include transition(visibility 0s linear 0.3s);
&.is-open {
visibility: visible;
#include transition-delay(0s);
.sidebar-content {
#include transform(translateX(0));
}
}
}
The isOpen prop in Sidebar adds class is-open to root element of Sidebar component. Here is Sidebar component for reference:
const Sidebar = props =>
<aside className={`sidebar ${props.isOpen ? ' is-open' : ''}`}>
<SidebarContent>{props.children}</SidebarContent>
</aside>
;
For testing to see whether it is a React problem, I added a button like the following to my App component:
constructor(props) {
super(props);
this.enableSidebar = this.enableSidebar.bind(this);
this.state = { isOpen: false };
}
enableSidebar() {
this.setState({ isOpen: true });
}
render() {
const sidebarProps = { isOpen: this.state.isOpen };
return (
<div className="app">
<button onClick={this.enableSidebar}>Enable Sidebar</button>
<Home />
<Sidebar {...sidebarProps}>{this.props.children></Sidebar>
</div>
);
}
And when I click the button, sidebar opens smoothly. It is React Router that completely reloads the page on every request, making every page be a static page instead of creating a dynamic application.
How can I change this behavior? How can I make React Router to not reload all components on route change? I am thinking that maybe the structure that I have is problematic. If you also think it is, can you suggest me a solution?
I have found the problem. I had to use React Router Link component instead of HTML anchor element. So instead of using:
About
I have to use:
<Link to="/en/pages/about-page">About</Link>

How to make a sticky footer in react?

I've made a sticky footer higher-level component that wraps other components inside itself:
Footer.js
//this is a higher-order component that wraps other components placing them in footer
var style = {
backgroundColor: "#F8F8F8",
borderTop: "1px solid #E7E7E7",
textAlign: "center",
padding: "20px",
position: "fixed",
left: "0",
bottom: "0",
height: "60px",
width: "100%",
};
const Footer = React.createClass({
render: function() {
return (
<div style={style}>
{this.props.children}
</div>
);
}
});
export default Footer;
Usage:
<Footer><Button>test</Button></Footer>
But it is hiding the contents of the page:
This looks like a common problem, so I searched a bit and found this issue, where is FlexBox is recommended for the sticky footer. But at this demo the footer is at the very bottom of the page, while I need the footer to be always displayed on the page and the content being scrolled inside the above area (like in SO chat). In addition to that, there is an advice to change all the other components with custom stylesheet rules. Is it possible to achieve what I need using styling only the footer component so the code will remain modular?
Here's an idea (sandbox example link).
Include a phantom div in your footer component that represents the footer's position that other dom elements will respect (i.e. affecting page flow by not being position: 'fixed';).
var style = {
backgroundColor: "#F8F8F8",
borderTop: "1px solid #E7E7E7",
textAlign: "center",
padding: "20px",
position: "fixed",
left: "0",
bottom: "0",
height: "60px",
width: "100%",
}
var phantom = {
display: 'block',
padding: '20px',
height: '60px',
width: '100%',
}
function Footer({ children }) {
return (
<div>
<div style={phantom} />
<div style={style}>
{ children }
</div>
</div>
)
}
export default Footer
Much easier idea (following the trend), i imported both bootstrap and reactstrap, used the bootstrap fixed bottom class and workaround with that like this.
class AppFooter extends Component{
render() {
return(
<div className="fixed-bottom">
<Navbar color="dark" dark>
<Container>
<NavbarBrand>Footer</NavbarBrand>
</Container>
</Navbar>
</div>
)
}
There is a much simpler way. I am creating a portfolio site with React, and some of my pages are not very long, so in some devices, like kindle fire hd for example, the footer would not stick to the bottom. And of course to set this up in the traditional fashion with would not work, because the would be wrapped in there. And we don't want that. So this is what I did:
In App.js:
import React, { Component } from 'react';
import {Header} from './components/Header';
import {Main} from './components/Main';
import {Footer} from './components/Footer';
class App extends Component {
render() {
return (
<div className="App Site">
<div className="Site-content">
<div className="App-header">
<Header />
</div>
<div className="main">
<Main />
</div>
</div>
<Footer />
</div>
);
}
}
export default App;
And then in _sticky-footer.css (I use POSTCSS):
:root {
--space: 1.5em 0;
--space: 2em 0;
}
.Site {
display: flex;
flex-direction: column;
min-height: 100vh;
}
.Site-content {
flex: 1 0 auto;
padding: var(--space) var(--space) 0;
width: 100%;
}
.Site-content:after {
content: '\00a0';
display: block;
margin-top: var(--space);
height: 0;
visibility: hidden;
}
The original solution for this was created by Philip Walton: https://philipwalton.github.io/solved-by-flexbox/demos/sticky-footer/
You can fix this by adding margin-bottom: 60px; to the body of your website. With the 60px being the height of your footer.
.footer{
width: 100%;
position: fixed;
bottom: 0;
}
This should do the trick! Cheers! (:
.App will be the main component you load to your Root.
Assume that the footer is the last child of .App in the document flow
.App {
height: 100vh;
display: flex;
flex-direction: column;
}
footer {
margin-top: auto;
}
I found that if you wrap your 'footer' component in a standard html
<footer>
tag, it pretty much sorts out all of the positioning for you
I wanted to share this solution that worked. I cribbed this from https://react.semantic-ui.com/modules/sticky. Scroll to the bottom of this page and inspect the text 'This is the bottom' to see where I stole it. Its a site built on react so it should work for your situation.
Here it is:
{
padding-top: 50vh;
}
Conceptually, this solution is creating negative space like jacoballenwood's phantom div to push the footer down to the bottom and stick it there. Just add it to your css style class for the footer and adjust the value to taste.
Very late answer, but someone can find this useful. You can, instead of phantom style, set Toolbar. I have build some standard layout for the components, where {children} is component from the parent component - App.js. This is example:
import React from "react";
import { Route } from "react-router-dom";
import { makeStyles } from "#material-ui/core/styles";
import AppBar from "#material-ui/core/AppBar";
import CssBaseline from "#material-ui/core/CssBaseline";
import Toolbar from "#material-ui/core/Toolbar";
import Header from "../components/header";
import Footer from "../components/footer";
import SideBar from "../components/sidebar";
const useStyles = makeStyles((theme) => ({
root: {
display: "flex",
},
appBar: {
zIndex: theme.zIndex.drawer + 1,
},
content: {
flexGrow: 5,
padding: theme.spacing(3),
},
}));
const StandardLayout = ({ children }) => {
const classes = useStyles();
return (
<div className={classes.root}>
<CssBaseline />
<AppBar position="fixed" className={classes.appBar}>
<Route path="/" component={Header} />
</AppBar>
<SideBar />
<main className={classes.content}>
<Toolbar />
<br />
{children}
<Toolbar/>
</main>
<AppBar className={classes.appBar}>
<Route path="/" component={Footer} />
</AppBar>
</div>
);
};
export default StandardLayout;
Its rule for me
<footer style={{position:"fixed",bottom:"0"}}>
Try this html code:
/public/index.html
<html lang="en" class="h-100">
<body class="h-100">
<div id="root" class="d-flex flex-column h-100"></div>
...
/src/App.js
<main role='main' className='flex-shrink-0'>
You can follow this template:
react-bootstrap-sticky-footer/public/index.html
react-bootstrap-sticky-footer/src/App.js

Resources