Estilos CSS en línea en React: ¿cómo implementar un: hover?

178

Me gusta bastante el patrón CSS en línea en React y decidí usarlo.

Sin embargo, no puede usar los :hoverselectores y similares. Entonces, ¿cuál es la mejor manera de implementar resaltar al pasar el mouse mientras se usan estilos CSS en línea?

Una sugerencia de #reactjs es tener un Clickablecomponente y usarlo así:

<Clickable>
    <Link />
</Clickable>

El Clickabletiene un hoveredestado y lo pasa como accesorios al Enlace. Sin embargo, el Clickable(la forma en que he implementado) envuelve al Linkde una divmanera que pueda establecer onMouseEntery onMouseLeavea la misma. Sin embargo, esto hace las cosas un poco más complicadas (por ejemplo, spanenvuelto en un divcomportamiento diferente al span).

¿Hay alguna forma más simple?

fhucho
fuente
1
Tiene toda la razón: la única forma de simular: desplazar, etc., los selectores con estilos en línea es usar onMouseEntery onMouseLeave. En cuanto a la implementación exacta de eso, depende totalmente de usted. Para ver su ejemplo específico, ¿por qué no hacer el <Clickable/>envoltorio a span?
Chris Houghton
3
sugeriría usar hojas de estilo externas junto con el complemento ExtractText Webpack, esto lo ayudará en una ejecución más larga si alguna vez desea ServerRender; de lo contrario, puede probar Radium github.com/FormidableLabs/radium
abhirathore2006
Actualmente, Styled Component es la mejor solución para simular todas las posibilidades de css / scss en react.
Ahmad Behzadi

Respuestas:

43

Estoy en la misma situación. Realmente me gusta el patrón de mantener el estilo en los componentes, pero los estados de desplazamiento parecen ser el último obstáculo.

Lo que hice fue escribir un mixin que puedes agregar a tu componente que necesita estados flotantes. Este mixin agregará una nueva hoveredpropiedad al estado de su componente. Se establecerá truesi el usuario se desplaza sobre el nodo DOM principal del componente y lo vuelve a establecer falsesi los usuarios abandonan el elemento.

Ahora en la función de renderización de componentes puede hacer algo como:

<button style={m(
     this.styles.container,
     this.state.hovered && this.styles.hover,
)}>{this.props.children}</button>

Ahora, cada vez que el estado del hoveredestado cambia, el componente volverá a aparecer.

También he creado un repositorio de sandbox para esto que utilizo para probar algunos de estos patrones yo mismo. Compruébalo si quieres ver un ejemplo de mi implementación.

https://github.com/Sitebase/cssinjs/tree/feature-interaction-mixin

Wim Mostmans
fuente
3
no es una buena solución para largo plazo, el radio será mejor elección o el uso de una hoja de estilo externa
abhirathore2006
16
@ abhirathore2006 radio funciona de la misma manera y la pregunta es específicamente cómo hacer esto sin necesidad de utilizar una hoja de estilo externa
Charlie Martin
¿No tendría más sentido usar un operador de vainilla?
PAT-O-MATION
102

Creo que onMouseEnter y onMouseLeave son los caminos a seguir, pero no veo la necesidad de un componente de contenedor adicional. Así es como lo implementé:

var Link = React.createClass({
  getInitialState: function(){
    return {hover: false}
  },
  toggleHover: function(){
    this.setState({hover: !this.state.hover})
  },
  render: function() {
    var linkStyle;
    if (this.state.hover) {
      linkStyle = {backgroundColor: 'red'}
    } else {
      linkStyle = {backgroundColor: 'blue'}
    }
    return(
      <div>
        <a style={linkStyle} onMouseEnter={this.toggleHover} onMouseLeave={this.toggleHover}>Link</a>
      </div>
    )
}

Luego puede usar el estado de desplazamiento (verdadero / falso) para cambiar el estilo del enlace.

Jonathan
fuente
1
Esto parecería cubrir :hoverpero no:focus
Adam Tuttle
3
@AdamTuttle react tiene un onFocusevento; por lo que podría hacer lo mismo para los :focusque :hover, excepto que en lugar de necesitar onMouseEntery onMouseLeavesólo necesitaríaonFocus
Jonathan
77
Tenga en cuenta que este método fuerza la ejecución en el hilo principal, mientras que los eventos CSS típicos se manejan de manera mucho más eficiente.
Hampus Ahlgren
54

Tarde para la fiesta pero ven con la solución. Puede usar "&" para definir estilos para pasar el mouse sobre nth Child, etc.

day: {
    display: "flex",
    flex: "1",
    justifyContent: "center",
    alignItems: "center",
    width: "50px",
    height: "50px",
    transition: "all 0.2s",
    borderLeft: "solid 1px #cccccc",

    "&:hover": {
      background: "#efefef"
    },
    "&:last-child": {
      borderRight: "solid 1px #cccccc"
    }
},
Hitesh Sahu
fuente
1
Esta no es una solución, la pregunta era cómo hacerlo con INLINE css, no con una hoja de estilo separada.
Emmy
36
Amigo, mira más de cerca. Este es un estilo en línea.
Jarosław Wlazło
15
Esto no funciona con React. Necesita una biblioteca adicional como componentes con estilo.
GG.
3
No funciona con estilo en línea, este ejemplo trae confusión. Si realmente funciona, proporcione un mejor ejemplo con el componente completo.
Alexandre
2
¡Excelente! ¡Funciona de maravilla!
Fyodor
26

Puede usar Radium: es una herramienta de código abierto para estilos en línea con ReactJS. Agrega exactamente los selectores que necesita. Muy popular, échale un vistazo - Radio en npm

Gyro
fuente
Acabo de encontrar esta publicación, ¿cómo implementaría Radium en la siguiente situación? module.exports = React.createClass({ displayName: 'App',})
1
@Rkhayat Puede envolverlo module.exports = Radium(React.createClass({ displayName: 'App',}))o asignarle la clase a un valor y agregar el @Radiumdecorador encima, ya que los documentos mencionan github.com/FormidableLabs/radium#usage
pbojinov
también existe esta gran cosa llamada CSS;)
Pixelomo
11

El soporte completo de CSS es exactamente la razón por la que esta gran cantidad de bibliotecas CSSinJS, para hacer esto de manera eficiente, necesita generar CSS real, no estilos en línea. También los estilos en línea son mucho más lentos en reaccionar en un sistema más grande. Descargo de responsabilidad: mantengo JSS .

Oleg Isonen
fuente
9

Made Style It , en parte, por esta razón (otros están en desacuerdo con la implementación de otras librerías / sintaxis y estilos en línea falta de soporte para prefijar valores de propiedad). Creemos que deberíamos poder simplemente escribir CSS en JavaScript y tener componentes totalmente autónomos HTML-CSS-JS. ¡Con las cadenas de plantilla ES5 / ES6 ahora podemos y también puede ser bonito! :)

npm install style-it --save

Sintaxis Funcional ( JSFIDDLE )

import React from 'react';
import Style from 'style-it';

class Intro extends React.Component {
  render() {
    return Style.it(`
      .intro:hover {
        color: red;
      }
    `,
      <p className="intro">CSS-in-JS made simple -- just Style It.</p>
    );
  }
}

export default Intro;

Sintaxis JSX ( JSFIDDLE )

import React from 'react';
import Style from 'style-it';

class Intro extends React.Component {
  render() {
    return (
      <Style>
      {`
        .intro:hover {
          color: red;
        }
      `}

        <p className="intro">CSS-in-JS made simple -- just Style It.</p>
      </Style>
    );
  }
}

export default Intro;
Joshua Robinson
fuente
Noté que en el ejemplo de sintaxis JSX, el enlace JSFiddle tiene el código correcto, pero al ejemplo que se muestra aquí le falta el paréntesis de cierre después de la etiqueta de estilo de cierre y la sangría está desactivada probablemente debido al paréntesis faltante.
bradleygsmith
8

Además de la respuesta de Jonathan , aquí están los eventos para cubrir el enfoque y los estados activos, y un uso en onMouseOverlugar de onMouseEnterya que este último no burbujeará si tiene elementos secundarios dentro del objetivo al que se aplica el evento.

var Link = React.createClass({

  getInitialState: function(){
    return {hover: false, active: false, focus: false}
  },

  toggleHover: function(){
    this.setState({hover: !this.state.hover})
  },

  toggleActive: function(){
    this.setState({active: !this.state.active})
  },

  toggleFocus: function(){
    this.setState({focus: !this.state.focus})
  },

  render: function() {
    var linkStyle;
    if (this.state.hover) {
      linkStyle = {backgroundColor: 'red'}
    } else if (this.state.active) {
      linkStyle = {backgroundColor: 'blue'}
    } else if (this.state.focus) {
      linkStyle = {backgroundColor: 'purple'}
    } 

    return(
      <div>
        <a style={linkStyle} 
          onMouseOver={this.toggleHover} 
          onMouseOut={this.toggleHover} 
          onMouseUp={this.toggleActive} 
          onMouseDown={this.toggleActive} 
          onFocus={this.toggleFocus}> 
          Link 
        </a>
      </div>
    )
  }
Rachel Cantor
fuente
7

Aquí está mi solución usando React Hooks. Combina el operador de propagación y el operador ternario.

style.js

export default {
  normal:{
    background: 'purple',
    color: '#ffffff'
  },
  hover: {
    background: 'red'
  }
}

Button.js

import React, {useState} from 'react';
import style from './style.js'

function Button(){

  const [hover, setHover] = useState(false);

  return(
    <button
      onMouseEnter={()=>{
        setHover(true);
      }}
      onMouseLeave={()=>{
        setHover(false);
      }}
      style={{
        ...style.normal,
        ...(hover ? style.hover : null)
      }}>

        MyButtonText

    </button>
  )
}
PAT-O-MATION
fuente
6

En lo que respecta a los componentes con estilo y react-router v4 , puede hacer esto:

import {NavLink} from 'react-router-dom'

const Link = styled(NavLink)`     
  background: blue;

  &:hover {
    color: white;
  }
`

...
<Clickable><Link to="/somewhere">somewhere</Link></Clickable>
Isaac Pak
fuente
6

Este puede ser un buen truco para tener un estilo en línea dentro de un componente de reacción (y también usar la función CSS: hover):

...

<style>
  {`.galleryThumbnail.selected:hover{outline:2px solid #00c6af}`}
</style>

...
tomericco
fuente
5

Pedido Typestyle si está utilizando reaccionar con Letra de imprenta.

A continuación se muestra un código de muestra para: hover

import {style} from "typestyle";

/** convert a style object to a CSS class name */
const niceColors = style({
  transition: 'color .2s',
  color: 'blue',
  $nest: {
    '&:hover': {
      color: 'red'
    }
  }
});

<h1 className={niceColors}>Hello world</h1>
paibamboo
fuente
4

Puede usar módulos css como alternativa, y adicionalmente react-css-modules para la asignación de nombres de clase.

De esa manera, puede importar sus estilos de la siguiente manera y usar un CSS normal con ámbito local para sus componentes:

import React from 'react';
import CSSModules from 'react-css-modules';
import styles from './table.css';

class Table extends React.Component {
    render () {
        return <div styleName='table'>
            <div styleName='row'>
                <div styleName='cell'>A0</div>
                <div styleName='cell'>B0</div>
            </div>
        </div>;
    }
}

export default CSSModules(Table, styles);

Aquí hay un ejemplo de módulos webpack css

svnm
fuente
FYI: Si está utilizando Meteor, consulte este paquete: github.com/nathantreid/meteor-css-modules . Lo estoy usando yo mismo teniendo gran éxito hasta ahora.
Spiralis
Esta es una excelente manera de diseñar componentes de reacción, pero no le da todo el control de los estilos en línea. Por ejemplo, no puede cambiar los :hoverestilos en tiempo de ejecución como puede hacerlo con Radium u otra onMouseOversolución basada
Charlie Martin el
4

onMouseOver y onMouseLeave con setState al principio me parecieron un poco costosos, pero como así es como funciona la reacción, me parece la solución más fácil y limpia.

Por ejemplo, renderizar un servidor CSS temático también es una buena solución y mantiene los componentes de reacción más limpios.

si no tiene que agregar estilos dinámicos a elementos (por ejemplo, para una temática), no debe usar estilos en línea, sino usar clases css.

Esta es una regla html / css tradicional para mantener html / JSX limpio y simple.

lukas gurschler
fuente
4

La manera simple es usar un operador ternario

var Link = React.createClass({
  getInitialState: function(){
    return {hover: false}
  },
  toggleHover: function(){
    this.setState({hover: !this.state.hover})
  },
  render: function() {
    var linkStyle;
    if (this.state.hover) {
      linkStyle = {backgroundColor: 'red'}
    } else {
      linkStyle = {backgroundColor: 'blue'}
    }
    return(
      <div>
        <a style={this.state.hover ? {"backgroundColor": 'red'}: {"backgroundColor": 'blue'}} onMouseEnter={this.toggleHover} onMouseLeave={this.toggleHover}>Link</a>
      </div>
    )
  }
Hemadri Dasari
fuente
1

Con un uso de los ganchos:

const useFade = () => {
  const [ fade, setFade ] = useState(false);

  const onMouseEnter = () => {
    setFade(true);
  };

  const onMouseLeave = () => {
    setFade(false);
  };

  const fadeStyle = !fade ? {
    opacity: 1, transition: 'all .2s ease-in-out',
  } : {
    opacity: .5, transition: 'all .2s ease-in-out',
  };

  return { fadeStyle, onMouseEnter, onMouseLeave };
};

const ListItem = ({ style }) => {
  const { fadeStyle, ...fadeProps } = useFade();

  return (
    <Paper
      style={{...fadeStyle, ...style}}
      {...fadeProps}
    >
      {...}
    </Paper>
  );
};
Jaroslav
fuente
0

Utilizo una solución bastante hack-ish para esto en una de mis aplicaciones recientes que funciona para mis propósitos, y me parece más rápido que escribir funciones de configuración de desplazamiento personalizado en vanilla js (aunque, reconozco, tal vez no sea una mejor práctica en la mayoría de los entornos ..) Entonces, en caso de que todavía estés interesado, aquí va.

Creo un elemento padre solo por mantener los estilos javascript en línea, luego un hijo con un className o id en el que se enganchará mi hoja de estilo css y escribiré el estilo de desplazamiento en mi archivo css dedicado. Esto funciona porque el elemento hijo más granular recibe los estilos js en línea a través de la herencia, pero sus archivos de desplazamiento se anulan por el archivo css.

Básicamente, mi archivo CSS actual existe con el único propósito de mantener los efectos de desplazamiento, nada más. Esto lo hace bastante conciso y fácil de administrar, y me permite hacer el trabajo pesado en mis estilos de componentes React en línea.

Aquí hay un ejemplo:

const styles = {
  container: {
    height: '3em',
    backgroundColor: 'white',
    display: 'flex',
    flexDirection: 'row',
    alignItems: 'stretch',
    justifyContent: 'flex-start',
    borderBottom: '1px solid gainsboro',
  },
  parent: {
    display: 'flex',
    flex: 1,
    flexDirection: 'row',
    alignItems: 'stretch',
    justifyContent: 'flex-start',
    color: 'darkgrey',
  },
  child: {
    width: '6em',
    textAlign: 'center',
    verticalAlign: 'middle',
    lineHeight: '3em',
  },
};

var NavBar = (props) => {
  const menuOptions = ['home', 'blog', 'projects', 'about'];

  return (
    <div style={styles.container}>
      <div style={styles.parent}>
        {menuOptions.map((page) => <div className={'navBarOption'} style={styles.child} key={page}>{page}</div> )}
      </div>
    </div>
  );
};


ReactDOM.render(
  <NavBar/>,
  document.getElementById('app')
);
.navBarOption:hover {
  color: black;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>

<div id="app"></div>

Observe que el estilo en línea "hijo" no tiene un conjunto de propiedades "color". Si lo hiciera, esto no funcionaría porque el estilo en línea tendría prioridad sobre mi hoja de estilo.

witygass
fuente
0

No estoy 100% seguro de si esta es la respuesta, pero es el truco que uso para simular el CSS: efecto de desplazamiento con colores e imágenes en línea.

`This works best with an image`

class TestHover extends React.PureComponent {
render() {
const landingImage = {     
"backgroundImage": "url(https://i.dailymail.co.uk/i/pix/2015/09/01/18/2BE1E88B00000578-3218613-image-m-5_1441127035222.jpg)",
"BackgroundColor": "Red", `this can be any color`
"minHeight": "100%",
"backgroundAttachment": "fixed",
"backgroundPosition": "center",
"backgroundRepeat": "no-repeat",
"backgroundSize": "cover", 
"opacity": "0.8", `the hove trick is here in the opcaity slightly see through gives the effect when the background color changes`
    }

  return (
    <aside className="menu">
        <div className="menu-item">
          <div style={landingImage}>SOME TEXT</div>
        </div>
    </aside>
      ); 
  }
}
ReactDOM.render(
    <TestHover />,
  document.getElementById("root")
);

CSS:

.menu {
top: 2.70em;
bottom: 0px;
width: 100%;
position: absolute;
}

.menu-item {
cursor: pointer;
height: 100%;
font-size: 2em;
line-height: 1.3em;
color: #000;
font-family: "Poppins";
font-style: italic;
font-weight: 800;
text-align: center;
display: flex;
flex-direction: column;
justify-content: center;
}

Antes de flotar

.menu-item:nth-child(1) {
color: white;
background-color: #001b37;
} 

En vuelo estacionario

.menu-item:nth-child(1):hover {
color: green;
background-color: white;
}

Ejemplo: https://codepen.io/roryfn/pen/dxyYqj?editors=0011

Rory
fuente
0
<Hoverable hoverStyle={styles.linkHover}>
  <a href="https://example.com" style={styles.link}>
    Go
  </a>
</Hoverable>

Donde Hoverable se define como:

function Hoverable(props) {
  const [hover, setHover] = useState(false);

  const child = Children.only(props.children);

  const onHoverChange = useCallback(
    e => {
      const name = e.type === "mouseenter" ? "onMouseEnter" : "onMouseLeave";
      setHover(!hover);
      if (child.props[name]) {
        child.props[name](e);
      }
    },
    [setHover, hover, child]
  );

  return React.cloneElement(child, {
    onMouseEnter: onHoverChange,
    onMouseLeave: onHoverChange,
    style: Object.assign({}, child.props.style, hover ? props.hoverStyle : {})
  });
}
Sig
fuente