API Essentials

Media Queries

Styleframe media queries enable responsive design with type-safe breakpoint definitions. Create adaptive layouts that work seamlessly across all device sizes.

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;

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.

Pro tip: Use consistent breakpoint values throughout your project. Consider defining them as variables to maintain consistency.

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;

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;

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;

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;

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;

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