admin管理员组文章数量:1391995
I am trying to create responsive props for styled ponents as follows. To start with, we have a ponent (let's say a button):
<Button primary large>Click Me</Button>
This button will get a background-color of primary and a large size (as determined by a theme file).
I now want to create a responsive version of this button. This is how I would like that to work:
<Button
primary
large
mobile={{size: 'small', style: 'secondary'}}
tablet={size: 'small'}}
widescreen={{style: 'accent'}}
>
Click Me
</Button>
I now have my same button, but with the styles and sizes varied for different screen sizes.
Now, I have gotten this to work -- but it involves a lot of duplicate code. This is an example of what it looks like:
const Button = styled('button')(
({
mobile,
tablet,
tabletOnly,
desktop,
widescreen
}) => css`
${mobile &&
css`
@media screen and (max-width: ${theme.breakpoints.mobile.max}) {
background-color: ${colors[mobile.style] || mobile.style};
border: ${colors[mobile.style] || mobile.style};
border-radius: ${radii[mobile.radius] || mobile.radius};
color: ${mobile.style && rc(colors[mobile.style] || mobile.style)};
}
`}
${tablet &&
css`
@media screen and (min-width: ${theme.breakpoints.tablet.min}), print {
background-color: ${colors[tablet.style] || tablet.style};
border: ${colors[tablet.style] || tablet.style};
border-radius: ${radii[tablet.radius] || tablet.radius};
color: ${tablet.style && rc(colors[tablet.style] || tablet.style)};
}
`}
${tabletOnly &&
css`
@media screen and (min-width: ${theme.breakpoints.mobile.min}) and (max-width: ${theme.breakpoints.tablet.max}) {
background-color: ${colors[tabletOnly.style] || tabletOnly.style};
border: ${colors[tabletOnly.style] || tabletOnly.style};
border-radius: ${radii[tabletOnly.radius] || tabletOnly.radius};
color: ${tabletOnly.style &&
rc(colors[tabletOnly.style] || tabletOnly.style)};
}
`}
`
What I am looking for is a way to simplify this code. Basically, I want to only write the CSS styles ONCE and then generate the different props and media queries based off of a query object that something like this:
const mediaQueries = {
mobile: {
min: '0px',
max: '768px'
},
tablet: {
print: true,
min: '769px',
max: '1023px'
},
desktop: {
min: '1024px',
max: '1215px'
},
widescreen: {
min: '1216px',
max: '1407px'
},
fullhd: {
min: '1408px',
max: null
}
}
I imagine I should be able to create a function that loops through through the mediaQueries
object and inserts the appropriate css for each iteration. However, I can't seem to figure out how to do this.
Any ideas on how to do this?
Also, thanks in advance for any help you can offer.
I am trying to create responsive props for styled ponents as follows. To start with, we have a ponent (let's say a button):
<Button primary large>Click Me</Button>
This button will get a background-color of primary and a large size (as determined by a theme file).
I now want to create a responsive version of this button. This is how I would like that to work:
<Button
primary
large
mobile={{size: 'small', style: 'secondary'}}
tablet={size: 'small'}}
widescreen={{style: 'accent'}}
>
Click Me
</Button>
I now have my same button, but with the styles and sizes varied for different screen sizes.
Now, I have gotten this to work -- but it involves a lot of duplicate code. This is an example of what it looks like:
const Button = styled('button')(
({
mobile,
tablet,
tabletOnly,
desktop,
widescreen
}) => css`
${mobile &&
css`
@media screen and (max-width: ${theme.breakpoints.mobile.max}) {
background-color: ${colors[mobile.style] || mobile.style};
border: ${colors[mobile.style] || mobile.style};
border-radius: ${radii[mobile.radius] || mobile.radius};
color: ${mobile.style && rc(colors[mobile.style] || mobile.style)};
}
`}
${tablet &&
css`
@media screen and (min-width: ${theme.breakpoints.tablet.min}), print {
background-color: ${colors[tablet.style] || tablet.style};
border: ${colors[tablet.style] || tablet.style};
border-radius: ${radii[tablet.radius] || tablet.radius};
color: ${tablet.style && rc(colors[tablet.style] || tablet.style)};
}
`}
${tabletOnly &&
css`
@media screen and (min-width: ${theme.breakpoints.mobile.min}) and (max-width: ${theme.breakpoints.tablet.max}) {
background-color: ${colors[tabletOnly.style] || tabletOnly.style};
border: ${colors[tabletOnly.style] || tabletOnly.style};
border-radius: ${radii[tabletOnly.radius] || tabletOnly.radius};
color: ${tabletOnly.style &&
rc(colors[tabletOnly.style] || tabletOnly.style)};
}
`}
`
What I am looking for is a way to simplify this code. Basically, I want to only write the CSS styles ONCE and then generate the different props and media queries based off of a query object that something like this:
const mediaQueries = {
mobile: {
min: '0px',
max: '768px'
},
tablet: {
print: true,
min: '769px',
max: '1023px'
},
desktop: {
min: '1024px',
max: '1215px'
},
widescreen: {
min: '1216px',
max: '1407px'
},
fullhd: {
min: '1408px',
max: null
}
}
I imagine I should be able to create a function that loops through through the mediaQueries
object and inserts the appropriate css for each iteration. However, I can't seem to figure out how to do this.
Any ideas on how to do this?
Also, thanks in advance for any help you can offer.
Share Improve this question asked Oct 27, 2019 at 16:14 MosheMoshe 7,05121 gold badges77 silver badges138 bronze badges2 Answers
Reset to default 5Maybe something like this is what you are looking for:
import { css } from "styled-ponents";
//mobile first approach min-width
const screenSizes = {
fullhd: 1408,
widescreen: 1215,
desktop: 1023,
tablet: 768,
mobile: 0
}
const media = Object
.keys(screenSizes)
.reduce((acc, label) => {
acc[label] = (...args) => css`
@media (min-width: ${screenSizes[label] / 16}rem) {
${css(...args)}
}
`
return acc
}, {});
Then you just import and use like so:
import media from './media'
const button = styled.button`
${({large , small})=> media.mobile`
color: red;
font-size: ${large ? '2em' : '1em'};
`}
`
Here's some further reading including using with theming:
Media queries in styled-ponents
Utilizing Props:
Using the same media query object from above:
Create a helper function to format the styles object to a css string:
const formatCss = (styleObject) => {
return JSON.stringify(styleObject)
.replace(/[{}"']/g,'')
.replace(/,/g,';')
+ ';'
}
Create another helper function to map over the styles and generate queries by mapping over its keys and using bracket notation dynamically add queries:
const mapQueries = (myQueries) =>{
return Object.keys(myQueries).map(key=> media[key]`
${formatCss(myQueries[key])}
`)
}
In your styled-ponent:
export const Button = styled.button`
${({myQueries}) => !myQueries ? '' : mapQueries(myQueries)}
`
Finally add a myQueries prop to your ponent like so (notice the use of css-formatted
keys instead of javascriptFormatted
keys for simplicity):
<Button myQueries={{
mobile:{ color:'red' },
tablet:{ color:'blue', "background-color":'green'},
desktop:{ height:'10rem' , width:'100%'}
}}>Button</Button>
For iterating through all your media queries, you can create a function similar to:
import { css } from "styled-ponents";
const sizes = {
desktop: 992,
tablet: 768,
phone: 576
};
// Iterate through the sizes and create a media template
const media = Object.keys(sizes).map(screenLabel => {
return {
query: (...args) => css`
@media (max-width: ${sizes[screenLabel] / 16}em) {
${css(...args)}
}
`,
screenLabel
};
});
export default media;
For usage in the ponent:
import media from "./media";
// The labels for this has to be same as the ones in sizes object
const colors = {
phone: "red",
tablet: "yellow",
desktop: "green"
};
const Heading = styled.h2`
color: blue;
${media.map(
({ query, screenLabel }) => query`
color: ${colors[screenLabel]};
`
)}
`;
本文标签: javascriptCreating Responsive Props for Styled ComponentsStack Overflow
版权声明:本文标题:javascript - Creating Responsive Props for Styled Components - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1744568857a2613217.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论