Tengo un Javascript que crea y mantiene una cadena de CSS, por ejemplo:
".joe{top:1rem} @media(min-width: 64rem){ .blogs{top:3rem} }" Parte de la lógica puede agregar una nueva regla CSS dentro de una consulta @media . Actualmente, agrega la regla después del corchete de apertura de la consulta @media , porque es muy fácil buscar @media(min-width: 64rem){ { luego insertar en ese índice, por ejemplo:
".joe{top:1rem} @media(min-width: 64rem){ .new{top:3rem} .blogs{top:3rem} }"Aquí hay un fragmento de la lógica:
// find the existing media query from the style tag // styleTagCache is the CSS string being maintained const searchString = `@media(min-width:${breakpoint}){`; const mqIndex = styleTagCache.indexOf(searchString) + searchString.length; // insert rule into the media query const styleTagArray = [...styleTagCache]; styleTagArray.splice(mqIndex, 0, ruleString); styleTagCache = styleTagArray.join(''); Sin embargo, me gustaría insertar la nueva regla al final de la consulta de medios, antes del corchete de cierre } , así:
".joe{top:1rem} @media(min-width: 64rem){ .blogs{top:3rem} .new{top:3rem} }" He tenido algunos intentos inútiles, pero no puedo resolverlo. La parte difícil parece ser buscar el cierre de la consulta de medios } , pero ignorar cualquier otro } que sea parte de las reglas CSS dentro de él.
Puede iterar sobre la cadena después de que ocurra la media query para encontrar el corchete de cierre y luego insertar la nueva regla:
const css = ".joe{top:1rem} @media(min-width: 64rem){ .blogs{top:3rem} }"; console.log(add(css, '64rem', '.new{top:3rem}')) function add(css, breakpoint, rule) { const niddle = `@media(min-width: ${breakpoint}){`; let index = css.indexOf(niddle); if (index === -1) throw new Error('Media query not found'); index += niddle.length; let balance = 0, pos = null; for (let i=index; i<css.length; i++) { const char = css[i]; if (char === '{') balance++; else if (char === '}') balance--; if (balance === -1) { pos = i-1; break; } } if (pos === null) throw new Error('Invalid css'); return css.substring(0, pos) + ` ${rule} ` + css.substring(pos); }No sé si esto es interesante para ti, pero en realidad puedes recorrer todas las reglas de CSS en JavaScript. Entonces, aquí busco e imprimo el color de fondo para una condición y agrego una nueva propiedad (el borde).
Dependiendo de la complejidad de su código, no es una tarea fácil encontrar la regla CSS correcta y modificarla, pero se puede hacer...
var cssRules = document.styleSheets[0].cssRules; // printout the background-color: console.log([...cssRules].filter(r => r.conditionText == '(min-width: 10rem)')[0].cssRules[0].style.backgroundColor); // add or modify a rule: [...cssRules].filter(r => r.conditionText == '(min-width: 10rem)')[0].cssRules[0].style.border = 'black solid 5px'; @media(min-width: 10rem) { .new { background-color: red; } } <div class="new">new</div>Creo que tendría sentido mantener un objeto que tenga todas las propiedades de esa regla @media. Luego puede agregar más selectores sobre la marcha y renderizar la cadena nuevamente usando la función.
El objeto que creé es simple. Puede hacer un objeto más avanzado si es necesario.
const renderrule = rule => { let selectorsstr = rule.selectors.map(s => `${s.selector}{${s.props}}`).join(' '); return `@media{(${rule.condition}) ${selectorsstr}}`; }; var mediarule = { condition: 'min-width: 64rem', selectors: [{ selector: '.blogs', props: 'top:3rem' }, { selector: '.new', props: 'top:3rem' } ] }; console.log(renderrule(mediarule)); // adding to the rule: mediarule.selectors.push({selector: '.new2', props: 'top:2rem'}); console.log(renderrule(mediarule));