Image 3D Hover Effect - css

I discovered this nice 3D Hover Image Effect - https://codepen.io/kw7oe/pen/mPeepv
With the help of tutorials and guides I know I can style a component with Materials UI and apply it this way the CSS what I do. In the example link the Image is declared as background in CSS. I did it not in CSS but with the MUI Image tag. However it does not throw errors but its not working at all and I am unsure as why.
For the information I build it in React TS.
import React from 'react';
import { Box, Typography } from '#mui/material';
import Image from 'mui-image';
const styles = {
body: {
background: '#ECECEC',
},
footer: {
width: '50%',
marginLeft: '25%',
textAlign: 'center',
fontFamily: 'Julius Sans One, sans-serif',
marginTop: '24px',
},
container: {
maxWidth: '720px',
margin: '24px auto 48px auto',
},
h1: {
fontFamily: 'Montserrat, sans-serif',
textTransform: 'uppercase',
},
h2: {
fontFamily: 'Julius Sans One, sans-serif',
fontSize: '2.5rem',
},
row: {
marginTop: '12px',
},
column: {
display: 'inlin-block',
textAlign: 'center',
},
figure: {
overflow: 'hidden',
},
'a:hover': {
textDecoration: 'none',
},
'column img': {
display: 'block',
width: '100%',
height: '300px',
},
tdimension: {
width: '300px',
height: '300px',
margin: '20px auto 40px auto',
perspective: '1000px',
},
'tdimension a ': {
display: 'block',
width: '100%',
height: '100%',
backgroundSize: 'cover',
transformStyle: 'preserve-3d',
transform: 'rotateX(70deg)',
transition: 'all 0.8s',
},
'tdimension:hover a': {
transform: 'rotateX(20deg)',
},
'tdimension a:after': {
content: '',
position: 'absolute',
left: 0,
bottom: 0,
width: '100%',
height: '40px',
background: 'linear-gradient(rgba(0, 0, 0, 0.2), rgba(0, 0, 0, 0.1))',
transform: 'rotateX(90deg)',
transformOrigin: 'bottom',
},
};
function Hover() {
return (
<Box style={styles.container}>
<Box style={styles.row}>
<Typography style={styles.h1}>Image Hover Effect</Typography> <Typography style={styles.h2}>3D Hover Effect</Typography>
</Box>
<Box style={styles.row}>
<Box style={styles.tdimension}>
<Image src="https://mir-s3-cdn-cf.behance.net/project_modules/disp/e8346826957515.56361c2106f3f.png" style={styles['tdimension a ']}/>
</Box>
</Box>
</Box>
);
}
export { Hover };

I would replace all style attributes with sx since MUI encourages the usage of sx prop and prefers it over style attribute:
https://mui.com/system/the-sx-prop/
I would also stick to the background url inside the <a/> since the 3D Hover Effect transformations are being applied to that tag.
return (
<Box sx={styles.container}>
<Box sx={styles.row}>
<Typography sx={styles.h1}>Image Hover Effect</Typography>
<Typography sx={styles.h2}>3D Hover Effect</Typography>
</Box>
<Box sx={styles.row}>
<Box sx={styles.tdimension}>
</Box>
<Divider sx={{ padding: "1px" }} />
</Box>
</Box>
);
Now inside your styles object wrap everything related to tdimension inside a nested styling object. Your <Box/> makes use of styles.tdimension and this way all your substyling won't get lost.
...
tdimension: {
width: "300px",
height: "300px",
margin: "20px auto 40px auto",
perspective: "1000px",
a: {
background:
'url("https://mir-s3-cdn-cf.behance.net/project_modules/disp/e8346826957515.56361c2106f3f.png")',
display: "block",
width: "100%",
height: "100%",
backgroundSize: "cover",
transformStyle: "preserve-3d",
transform: "rotateX(70deg)",
transition: "all 0.8s",
},
"&:hover a": {
transform: "rotateX(20deg)",
},
"a:after": {
content: '""',
position: "absolute",
left: 0,
bottom: 0,
width: "100%",
height: "40px",
background: "linear-gradient(rgba(0, 0, 0, 0.2), rgba(0, 0, 0, 0.1))",
transform: "rotateX(90deg)",
transformOrigin: "bottom",
},
},
The result should be pretty identical to the codepen now.

Related

material ui :nth-child() and nextjs is not working?

Hello and thank you for reading my question..
I am using NextJS for my personal website and material ui. Now I render dynamically some pieces of data and I want some children to be shown on a specific position using :nth-child but it doesn't seem to work.
The parent component is position relative and the element I am targeting is absolute. I tried different versions of it and some people's post here but it doesn't seem to be working.
Thank you very much :)
'&: first-child': {
top: '35%',
zIndex: 4,
},
'&: last-child': {
top: '20%',
zIndex: 4,
},
or
'&: nth-child(1)': {
top: '35%',
zIndex: 4,
},
'&: nth-child(2)': {
top: '20%',
zIndex: 4,
},
'&:nth-child(1)': {
top: '35%',
zIndex: 4,
},
'&:nth-child(2)': {
top: '20%',
zIndex: 4,
},
<Box
sx={{
display: 'flex',
flexWrap: 'wrap',
flexDirection: 'column',
alignItems: 'center',
justifyContent: 'center',
position: 'relative',
gap: 4,
}}
>
{projects.map(({ title, details, id, img }) => {
return (
<ScaleBox duration={1} delayOrder={rand(1, 12)}>
<Image
src={img}
alt="Picture of the author"
width={500}
height={500}
loading="eager"
priority={true}
className={classes.img}
/>
<Grid container className={classes.project} id="projects">
<div>
<Image src="/folder.svg" width={30} height={30} alt="project" />
</div>
<Typography className={classes.title}>{title}</Typography>
<Typography className={classes.details}>{details}</Typography>
</Grid>
</ScaleBox>
);
})}
```
The element that I want to apply the styles is the ``classes.project`` and I added below the selector styled:
```
project: {
position: 'absolute',
// top: '25%',
left: '55%',
flexDirection: 'column',
width: '600px',
height: '230px',
// maxWidth: '400px',
borderRadius: '8px',
padding: '25px',
background: '#161e26',
gap: 4,
cursor: 'pointer',
transition: 'ease 0.5s',
zIndex: 4,
boxShadow:
'rgb(0 0 0 / 20%) 0px 12px 28px 0px, rgb(0 0 0 / 10%) 0px 2px 4px 0px, rgb(116 116 116 / 5%) 0px 0px 0px 1px inset',
'&:hover': {
transform: 'translate(0, -20px)',
},
},
'&:nth-child(1)': {
top: '75%',
zIndex: 4,
},
'&:nth-child(2)': {
top: '50%',
zIndex: 4,
},

Material UI Advanced Button - Text Alignment for Small Screensizes

React / Material-UI Novice here. I am trying to configure a set of buttons inside my app Bar that have a background picture to make it look a little cleaner. I have used a lot of code from examples online (shock) and got it to a place where i am happy with how it has formatted on a full size view (md++). However, when i downsize it to a small breakpoint though, the button image then stack instead (which is what i want) but i lose my text to the left. I have tried shifting to the right in many different ways but i dont think thats the right way to do it, is there something i am missing in making the text flex, i want the text to be in the middle?
import React from 'react'
import { AppBar, Toolbar } from "#mui/material";
import { makeStyles } from '#mui/styles'
import Button from '#mui/material/Button'
import Stack from '#mui/material/Stack'
import ButtonBase from '#mui/material/ButtonBase';
import { styled } from '#mui/material/styles';
import Typography from '#mui/material/Typography';
import Box from '#mui/material/Box';
const useStyles = makeStyles(theme => ({
button: {
...theme.typography.mainmenu,
borderRadius: "40px",
marginLeft: "1px",
height: "45px",
"&:hover": {
backgroundColor: theme.palette.secondary
}
},
}))
const images = [
{
url: '/assets/breakfastMenu.jpg',
title: 'Breakfast',
width: '33.33%',
},
{
url: '/assets/steak.jpg',
title: 'Mains',
width: '33.33%',
},
{
url: '/assets/desserts.jpg',
title: 'Desserts',
width: '33.33%',
},
];
const Image = styled('span')(({ theme }) => ({
position: 'absolute',
left: 0,
right: 0,
top: 0,
bottom: 0,
display: 'flex',
alignItems: 'center',
justifyContent: 'space-between',
color: theme.palette.common.primary,
}));
const ImageButton = styled(ButtonBase)(({ theme }) => ({
position: 'relative',
height: 150,
[theme.breakpoints.down('sm')]: {
width: '100% !important', // Overrides inline-style
height: 100,
},
'&:hover, &.Mui-focusVisible': {
zIndex: 1,
'& .MuiImageBackdrop-root': {
opacity: 0.15,
},
'& .MuiImageMarked-root': {
opacity: 0,
},
'& .MuiTypography-root': {
border: '4px solid currentColor',
},
},
}));
const ImageSrc = styled('span')({
position: 'absolute',
left: 0,
right: 0,
top: 0,
bottom: 0,
backgroundSize: 'cover',
backgroundPosition: 'center 40%',
});
const ImageBackdrop = styled('span')(({ theme }) => ({
position: 'absolute',
left: 0,
right: 0,
top: 0,
bottom: 0,
backgroundColor: theme.palette.common.black,
opacity: 0.4,
transition: theme.transitions.create('opacity'),
}));
const ImageMarked = styled('span')(({ theme }) => ({
height: 3,
width: 18,
backgroundColor: theme.palette.common.white,
position: 'absolute',
bottom: -2,
left: 'calc(50% - 9px)',
transition: theme.transitions.create('opacity'),
}));
const Header = () => {
const classes = useStyles();
return (<React.Fragment><AppBar position="sticky" className={classes.appBar}>
<Toolbar disableGutters className={classes.mainToolbar} sx={{ justifyContent: "center" }}>
<Stack direction="row" justifyContent="space-between" alignItems="center" spacing={10}>
{/* <Button variant="contained" color="secondary" className={classes.button}>Breakfast</Button>
<Button variant="contained" color="secondary" className={classes.button}>Mains</Button>
<Button variant="contained" color="secondary" className={classes.button}>Desserts</Button> */}
<Box sx={{ display: 'flex', flexWrap: 'wrap', minWidth: 900, width: '100%' }}>
{images.map((image) => (
<ImageButton
focusRipple
key={image.title}
style={{
width: image.width,
}}
>
<ImageSrc style={{
backgroundImage: `url(${image.url})`
}} />
<ImageBackdrop className="MuiImageBackdrop-root" />
<Image>
<Typography
component="span"
variant="subtitle1"
color="white"
fontWeight="bold"
sx={{
position: 'relative',
p: "7em",
pt: "2em",
pb: (theme) => `calc(${theme.spacing(1)} + 6px)`,
}}
>
{image.title}
<ImageMarked className="MuiImageMarked-root" />
</Typography>
</Image>
</ImageButton>
))}
</Box>
</Stack>
</Toolbar>
</AppBar>
</React.Fragment >
)
}
export default Header
I have moved on from this, but in case anybody finds it, using MUI i completely adapted my application by using:
import useMediaQuery from '#mui/material/useMediaQuery'
and some example like:
const matches = useMediaQuery(theme.breakpoints.down("md"))
to control when the application changes its styles

Material UI Autocomplete margin sizing issue

I have the following issue. I'm using Material-UI Autocomplete in my project. I made some alterations so the font and the component resize when the viewport changes size. Thus I've used vw on widths,heights and font-sizes. However, as you can see in the gif bellow, when I resize the gap between the green sauce and the blue/red spaces increases. how can I make sure that the gap also follows the initial proportion? So basically what I would like is that the whole component shrunk and the gap didn't increase. I've been altering all kinds of heights/margins but I can't seem to solve the issue. You have all the code available on the following sand box.
https://2y3jh.csb.app
You need to alter the input height to 3vw so that the height is consistent.
import TextField from "#material-ui/core/TextField";
import Autocomplete from "#material-ui/lab/Autocomplete";
import { makeStyles } from "#material-ui/core/styles";
const useStyles = makeStyles({
input: {
width: "100%",
height: "3vw", // Changed from 2vw
fontSize: "1.25vw",
color: "#02112E",
backgroundColor: "green"
},
option: {
fontSize: "0.8vw",
height: "3vw",
width: "100%",
color: "#02112E"
},
noOption: {
fontSize: "0.8vw",
height: "3vw",
width: "100%",
color: "#02112E"
},
root: {
"& label + .MuiInput-formControl": {
marginTop: "1vw"
},
"& label.Mui-focused": {
color: "#02112E",
fontSize: "0.97vw"
},
"& .MuiInput-underline:after": {
borderBottomColor: "#02112E",
borderBottomWidth: "0.21vw",
left: "0",
transformOrigin: "left center",
transition: "all 0.3s ease"
},
"& .MuiInput-underline:before": {
borderBottomColor: "#02112E",
borderBottomWidth: "0.07vw"
},
"& .MuiInput-underline:hover::before": {
borderBottomColor: "#02112E",
borderBottomWidth: "0.07vw"
},
fontSize: "1.25vw",
width: "100%",
height: "3vw",
backgroundColor: "red"
},
inputRoot: {
color: "#02112E",
fontSize: "1.25vw",
backgroundColor: "blue",
transform: "translate(0, 2vw) scale(1)"
}
});
export default function StyledAutoComplete() {
const classes = useStyles();
return (
<Autocomplete
style={{ width: "60%" }}
options={list}
classes={{
root: classes.root,
option: classes.option,
noOptions: classes.noOption,
input: classes.input
}}
disableClearable
freeSolo
noOptionsText={"No Options"}
autoHighlight
getOptionLabel={(option) => option.title}
renderOption={(option) => <React.Fragment>{option.title}</React.Fragment>}
renderInput={(params) => (
<TextField
style={{ width: "100%" }}
{...params}
label="Option"
variant="standard"
inputProps={{
...params.inputProps,
autoComplete: "new-password" // disable autocomplete and autofill
}}
InputLabelProps={{
classes: {
root: classes.inputRoot
}
}}
/>
)}
/>
);
}
const list = [{ title: "opt 1" }, { title: "opt 2" }];
Demo: https://2zh36.csb.app/
Output:

React material ui appbar made responsive

I am trying to use material ui's appbar and code in some custom responsiveness to it. I am creating a personal project that will be accessed from a Galaxy s8 smartphone. Ultimately I would like the nav-links and logout button on the navbar to consolidate into a hamburger button when the viewport is small. I am not quite sure how to achieve this however as I am using flexbox on the webpage when it is at full size and it keeps messing me up.
Here is the appbar at full size:
Here is the appbar at phone size with the hamburger button:
Here is the desired effect I would like with items, posts, groups, and the log out button being pushed to an accordion like menu on mobile:
Here is my navbar component code:
import { withStyles } from "#material-ui/core/styles";
import styles from "./styles/NavBarStyles";
import { LoggedInContext } from "./contexts/LoggedIn";
import { ThemeContext } from "./contexts/ThemeContext";
function Navbar(props) {
const { isDarkMode, toggleTheme } = useContext(ThemeContext);
const { loggedIn, changeLogIn, token, setToken } = useContext(
LoggedInContext
);
const { classes } = props;
const [mobileHamburgerOpen, setMobileHamburger] = useState(false);
const handleMobileClick = () => {
setMobileHamburger(!mobileHamburgerOpen);
console.log(mobileHamburgerOpen);
};
return (
<div className={classes.root}>
<AppBar
position="static"
style={{ background: isDarkMode ? "#2E3B55" : "#715AFF" }}
>
<Toolbar>
<Typography className={classes.title} variant="h6" color="inherit">
{isDarkMode ? "🌚" : "🌞"}
</Typography>
<Switch onChange={toggleTheme} />
<div className={classes.grow} />
{loggedIn && (
<div className={classes.loggedIn}>
<div className={classes.navlinks}>
<NavLink
to="/items"
activeStyle={{ background: "rgba(0, 0, 0, 0.5)" }}
>
Items
</NavLink>
<NavLink
to="/facebookitems"
activeStyle={{ background: "rgba(0, 0, 0, 0.5)" }}
>
<i className="fab fa-facebook-square"></i> Posts
</NavLink>
<NavLink
to="/groups"
activeStyle={{ background: "rgba(0, 0, 0, 0.5)" }}
>
<i className="fab fa-facebook-square"></i> Groups
</NavLink>
</div>
<Button
className={classes.logOutButton}
variant="contained"
color="secondary"
onClick={handleClick}
>
Log Out
</Button>
<Button
className={classes.hamburgerMenu}
variant="contained"
color="primary"
onClick={handleMobileClick}
>
<i className="fas fa-bars"></i>
</Button>
</div>
)}
</Toolbar>
</AppBar>
</div>
);
}
export default withStyles(styles)(Navbar);
Here is my style sheet code:
import { fade } from "#material-ui/core/styles/colorManipulator";
const styles = theme => ({
root: {
width: "100%",
marginBottom: 0
},
grow: {
flexGrow: 1
},
menuButton: {
marginLeft: -12,
marginRight: 20
},
title: {
display: 'block'
},
search: {
position: "relative",
borderRadius: theme.shape.borderRadius,
backgroundColor: fade(theme.palette.common.white, 0.15),
"&:hover": {
backgroundColor: fade(theme.palette.common.white, 0.25)
},
marginLeft: 0,
width: "100%",
[theme.breakpoints.up("sm")]: {
marginLeft: theme.spacing(1),
width: "auto"
}
},
searchIcon: {
width: theme.spacing(9),
height: "100%",
position: "absolute",
display: "flex",
alignItems: "center",
justifyContent: "center"
},
inputRoot: {
color: "inherit",
width: "100%"
},
inputInput: {
paddingTop: theme.spacing(1),
paddingRight: theme.spacing(1),
paddingBottom: theme.spacing(1),
paddingLeft: theme.spacing(10),
transition: theme.transitions.create("width"),
width: "100%",
[theme.breakpoints.up("sm")]: {
width: 120,
"&:focus": {
width: 200
}
}
},
loggedIn: {
width: "100%",
display: "flex",
justifyContent: "space-between",
alignItems: "center",
paddingLeft: "2rem"
},
navlinks: {
// [theme.breakpoints.down("sm")]: {
// position: 'absolute',
// backgroundColor: "rgba(0,0,0,.7)",
// top: '0%',
// right: '0%',
// width: '100vw',
// height: '100vh'
// },
"& a": {
color: "white",
fontWeight: "bold",
fontSize: "1.5rem",
textDecoration: "none",
marginRight: '1rem',
padding: ".5rem",
borderRadius: "15px"
},
"& a:active": {
backgroundColor: "rgba(0, 0, 0, 0.5)"
}
},
hamburgerMenu: {
display: 'none',
[theme.breakpoints.down("sm")]: {
display: 'block',
marginLeft: "auto",
backgroundColor: "white",
color: "#715AFF"
}
},
logOutButton: {
// [theme.breakpoints.down("sm")]: {
// display: 'none'
// }
}
});
export default styles;

MUI Card text overlay

I'm using the MUI Card and CardMedia components in my app but can't figure out how to overlay text on top of the image. This is a simplified example of what I'm trying:
<Card>
<CardMedia image={this.props.preview} style={styles.media}/>
<div style={styles.overlay}>
this text should overlay the image
</div>
</Card>
const styles = {
media: {
height: 0,
paddingTop: '56.25%' // 16:9
},
overlay: {
position: 'relative',
top: '20px',
left: '20px',
color: 'black',
backgroundColor: 'white'
}
}
I've tried placing the text div in above the CardMedia, below it, inside it, outside the Card entirely, and using different position values but can't figure this out at all. The beta versions of MUI included an overlay property on the CardMedia, but the v1 library doesn't seem to have anything like that.
Any know how to properly do this? Thanks in advance for any help!
Your CSS is off, you'll want to absolutely position the styles.overlay, and make sure the Card is position relative
Try something like this:
<Card style={styles.card}>
<CardMedia image={this.props.preview} style={styles.media}/>
<div style={styles.overlay}>
this text should overlay the image
</div>
</Card>
const styles = {
media: {
height: 0,
paddingTop: '56.25%' // 16:9
},
card: {
position: 'relative',
},
overlay: {
position: 'absolute',
top: '20px',
left: '20px',
color: 'black',
backgroundColor: 'white'
}
}
Use the code below if you want to have an overlay like the Card in version 0. Remember to set the position of the container to relative so the absolute position of the overlay can take effect:
<Card sx={{ maxWidth: 345 }}>
<Box sx={{ position: 'relative' }}>
<CardMedia
component="img"
height="200"
image="https://mui.com/static/images/cards/contemplative-reptile.jpg"
/>
<Box
sx={{
position: 'absolute',
bottom: 0,
left: 0,
width: '100%',
bgcolor: 'rgba(0, 0, 0, 0.54)',
color: 'white',
padding: '10px',
}}
>
<Typography variant="h5">Lizard</Typography>
<Typography variant="body2">Subtitle</Typography>
</Box>
</Box>
{...}
</Card>

Resources