Media Queries
Overview
Media queries in Styleframe provide a powerful way to create responsive designs with full type safety and auto-complete. You can define breakpoints and create adaptive layouts that work seamlessly across all device sizes while maintaining the benefits of Styleframe's TypeScript support.
Why use media queries?
Media queries help you:
- Create responsive designs: Build layouts that adapt perfectly to different screen sizes and devices.
- Maintain design consistency: Use variables and tokens to ensure consistent spacing and sizing across breakpoints.
- Write maintainable code: Leverage type safety and organized structure to prevent common responsive design mistakes.
- Optimize performance: Generate clean, efficient CSS that loads quickly on all devices.
Defining Media Queries
You define media queries using the media()
function from your styleframe instance:
import { styleframe } from 'styleframe';
const s = styleframe();
const { selector, media } = s;
selector('.container', {
width: '100%',
padding: '1rem',
});
media('(min-width: 768px)', ({ selector }) => {
selector('.container', {
width: '750px',
margin: '0 auto',
});
});
media('(min-width: 1024px)', ({ selector }) => {
selector('.container', {
width: '980px',
padding: '2rem',
});
});
export default s;
.container {
width: 100%;
padding: 1rem;
}
@media (min-width: 768px) {
.container {
width: 750px;
margin: 0 auto;
}
}
@media (min-width: 1024px) {
.container {
width: 980px;
padding: 2rem;
}
}
The media()
function takes a media query string and a callback function that receives the styleframe context, allowing you to define selectors that will be wrapped in the media query.
Nesting Media Queries
You can nest media queries to create more specific targeting and improve readability:
a. Callback Nesting
For more complex nesting scenarios or when you need to generate media queries dynamically, you can use the callback-based approach.
import { styleframe } from 'styleframe';
const s = styleframe();
const { selector, media } = s;
selector('.container', {
width: '100%',
padding: '1rem',
}, ({ media }) => {
media('(min-width: 768px)', {
width: '750px',
margin: '0 auto',
});
media('(min-width: 1024px)', {
width: '980px',
padding: '2rem',
});
});
export default s;
.container {
width: 100%;
padding: 1rem;
@media (min-width: 768px) {
width: 750px;
margin: 0 auto;
}
@media (min-width: 1024px) {
width: 980px;
padding: 2rem;
}
}
b. Inline Nesting
Alternatively, you can use inline nesting syntax for simpler nested media query definitions:
import { styleframe } from 'styleframe';
const s = styleframe();
const { selector, media } = s;
selector('.container', {
width: '100%',
padding: '1rem',
'@media (min-width: 768px)': {
width: '750px',
margin: '0 auto',
},
'@media (min-width: 1024px)': {
width: '980px',
padding: '2rem',
}
});
export default s;
.container {
width: 100%;
padding: 1rem;
@media (min-width: 768px) {
width: 750px;
margin: 0 auto;
}
@media (min-width: 1024px) {
width: 980px;
padding: 2rem;
}
}
Examples
Breakpoint Variables
For better maintainability, define your breakpoints as variables and use them with the media()
function:
import { styleframe, css } from 'styleframe';
const s = styleframe();
const { variable, ref, selector } = s;
const breakpointXs = variable('breakpoint--xs', 0, options);
const breakpointSm = variable('breakpoint--sm', 576, options);
const breakpointMd = variable('breakpoint--md', 992, options);
const breakpointLg = variable('breakpoint--lg', 1200, options);
const breakpointXl = variable('breakpoint--xl', 1440, options);
selector('.responsive-grid', {
display: 'grid',
gridTemplateColumns: '1fr',
gap: '1rem',
}, ({ media }) => {
media(css`(min-width: ${ref(breakpointSm)})`, {
gridTemplateColumns: 'repeat(2, 1fr)',
});
media(css`(min-width: ${ref(breakpointLg)})`,{
gridTemplateColumns: 'repeat(4, 1fr)',
});
});
export default s;
:root {
--breakpoint--xs: 0;
--breakpoint--sm: 576px;
--breakpoint--md: 992px;
--breakpoint--lg: 1200px;
--breakpoint--xl: 1440px;
}
.responsive-grid {
display: grid;
grid-template-columns: 1fr;
gap: 1rem;
@media (min-width: 640px) {
grid-template-columns: repeat(2, 1fr);
}
@media (min-width: 1024px) {
grid-template-columns: repeat(4, 1fr);
}
}
Responsive Typography
You can also use media queries to create responsive typography that adapts to different screen sizes:
import { styleframe } from 'styleframe';
const s = styleframe();
const { selector, media } = s;
selector('.responsive-text', {
fontSize: '16px',
lineHeight: '1.5',
});
media('(min-width: 768px)', ({ selector }) => {
selector('.responsive-text', {
fontSize: '18px',
});
});
media('(min-width: 1024px)', ({ selector }) => {
selector('.responsive-text', {
fontSize: '20px',
});
});
export default s;
.responsive-text {
font-size: 16px;
line-height: 1.5;
}
@media (min-width: 768px) {
.responsive-text {
font-size: 18px;
}
}
@media (min-width: 1024px) {
.responsive-text {
font-size: 20px;
}
}
Complex Media Queries
The media()
function supports all CSS media query features, including complex conditions:
import { styleframe } from 'styleframe';
const s = styleframe();
const { selector, media } = s;
selector('.adaptive-component', {
padding: '1rem',
backgroundColor: '#f5f5f5',
});
// Tablet landscape
media('(min-width: 768px) and (max-width: 1023px) and (orientation: landscape)', ({ selector }) => {
selector('.adaptive-component', {
padding: '1.5rem',
backgroundColor: '#e5e5e5',
});
});
// High DPI screens
media('(-webkit-min-device-pixel-ratio: 2), (min-resolution: 192dpi)', ({ selector }) => {
selector('.adaptive-component', {
backgroundImage: 'url("image@2x.png")',
});
});
// Dark mode preference
media('(prefers-color-scheme: dark)', ({ selector }) => {
selector('.adaptive-component', {
backgroundColor: '#1a1a1a',
color: '#ffffff',
});
});
// Reduced motion preference
media('(prefers-reduced-motion: reduce)', ({ selector }) => {
selector('.adaptive-component', {
transition: 'none',
animation: 'none',
});
});
export default s;
.adaptive-component {
padding: 1rem;
background-color: #f5f5f5;
}
@media (min-width: 768px) and (max-width: 1023px) and (orientation: landscape) {
.adaptive-component {
padding: 1.5rem;
background-color: #e5e5e5;
}
}
@media (-webkit-min-device-pixel-ratio: 2), (min-resolution: 192dpi) {
.adaptive-component {
background-image: url("image@2x.png");
}
}
@media (prefers-color-scheme: dark) {
.adaptive-component {
background-color: #1a1a1a;
color: #ffffff;
}
}
@media (prefers-reduced-motion: reduce) {
.adaptive-component {
transition: none;
animation: none;
}
}
Best Practices
- Use consistent breakpoints throughout your project by defining them as variables.
- Design mobile-first by starting with base styles and adding larger screen styles progressively.
- Group related responsive styles within the same
media()
function call for better organization. - Leverage the context parameter to access all styleframe functions within media queries.
- Test across devices to ensure your responsive design works as expected.
FAQ
Yes, the media()
function supports all standard CSS media query features including min-width
, max-width
, orientation
, prefers-color-scheme
, and more.
While CSS doesn't support nested media queries, you can combine multiple conditions in a single media query string passed to the media()
function.
The context parameter provides access to all styleframe functions including selector
, variable
, ref
, and even nested media
calls.
This depends on your design needs. rem
units respect user font size preferences, while px
units provide more predictable behavior. Choose based on your accessibility requirements.
Selectors
Styleframe selectors allow you to create CSS rules with type-safe property definitions. They provide a powerful way to style your components.
Keyframes
Styleframe keyframes enable you to create smooth CSS animations with type-safe property definitions. Build engaging motion effects that enhance user experience across your application.