Guia da propriedade CSS pointer-events
Overlay que bloqueia o clique no que está atrás, submenu invisível que continua interceptando o mouse: os dois problemas se resolvem com uma linha de pointer-events.
Só que a propriedade não desabilita eventos: ela muda qual elemento é escolhido como alvo. Entender essa diferença explica praticamente todo o comportamento dela.
A propriedade pointer-events controla se um elemento pode se tornar o alvo de eventos de ponteiro, como cliques, estados de hover e outros eventos baseados em ponteiro. Em outras palavras, ela permite decidir se o navegador deve tratar um elemento como interativo quando o ponteiro está sobre ele.
.no-pointer-events { pointer-events: none;}Para entender como a propriedade funciona, ajuda saber o que o navegador faz antes de disparar um evento de ponteiro. Primeiro, ele precisa determinar qual elemento está sob o ponteiro. Esse processo é conhecido como hit-testing.
Normalmente, o navegador escolhe o elemento mais ao topo sob o ponteiro. Mas, se esse elemento tiver pointer-events definido como none, o navegador o ignora e continua procurando o próximo elemento elegível abaixo dele.
Uma vez que se pensa em pointer-events dessa forma, a maior parte do comportamento dela começa a fazer sentido. Em vez de desabilitar eventos, ela simplesmente muda qual elemento (ou, no caso de SVG, qual parte de um elemento) se torna o alvo do evento.
Sintaxe
pointer-events: auto | bounding-box | visiblePainted | visibleFill | visibleStroke | visible | painted | fill | stroke | all | none;- Valor inicial: auto
- Aplica-se a: todos os elementos. Em SVG, aplica-se a elementos container, elementos gráficos e ao próprio elemento.
- Herdada: sim
- Valor computado: a palavra-chave especificada
- Tipo de animação: discreto
Valores
pointer-events: auto;pointer-events: none;
/* Valores de SVG */pointer-events: visiblePainted;pointer-events: visibleFill;pointer-events: visibleStroke;pointer-events: visible;pointer-events: painted;pointer-events: fill;pointer-events: stroke;pointer-events: bounding-box;pointer-events: all;
/* Valores globais */pointer-events: inherit;pointer-events: initial;pointer-events: revert;pointer-events: revert-layer;pointer-events: unset;Além dos valores globais padrão de CSS mostrados acima, a pointer-events define onze palavras-chave.
Você vai usar auto e none tanto com elementos HTML quanto SVG. As outras nove são exclusivas de SVG e oferecem controle mais fino sobre quais partes de um gráfico podem receber eventos de ponteiro.
auto: o valor padrão. O elemento se comporta normalmente e pode receber eventos de ponteiro. Em SVG, funciona igual avisiblePainted.none: o elemento em si não pode se tornar alvo de eventos de ponteiro, o que significa que ele não pode ser clicado nem receber hover. Em vez dele, o navegador mira no que estiver embaixo.
Valores exclusivos de SVG
visiblePainted: o elemento só recebe eventos de ponteiro quando está visível (visibility: visible) e o ponteiro está sobre uma parte pintada do gráfico. Ou seja, sobre uma área preenchida (filldiferente denone) ou sobre uma borda traçada (strokediferente denone).visibleFill: o elemento só recebe eventos de ponteiro quando está visível e o ponteiro está sobre o preenchimento dele, independentemente do valor da propriedadefill, que pode até estar comonone.visibleStroke: o elemento só recebe eventos de ponteiro quando está visível e o ponteiro está sobre o traço dele, independentemente do valor da propriedadestroke.visible: o elemento só recebe eventos de ponteiro quando está visível e o ponteiro está sobre o preenchimento ou o traço, independentemente dos valores das propriedadesfillestroke.painted: o elemento só recebe eventos de ponteiro quando o ponteiro está sobre uma parte pintada do gráfico (preenchimento ou traço), independentemente do valor da propriedadevisibility.fill: o elemento só recebe eventos de ponteiro quando o ponteiro está sobre o preenchimento dele, independentemente dos valores das propriedadesfillevisibility.stroke: o elemento só recebe eventos de ponteiro quando o ponteiro está sobre o traço dele, independentemente dos valores das propriedadesstrokeevisibility.bounding-box: o elemento recebe eventos de ponteiro em qualquer ponto dentro da bounding box dele (o menor retângulo que o cerca por completo), independentemente do formato, mesmo que partes dessa área não estejam pintadas.all: o elemento recebe eventos de ponteiro quando o ponteiro está sobre o preenchimento ou o traço dele, independentemente dos valores das propriedadesfill,strokeouvisibility.
Filhos podem voltar a participar
Algo fácil de deixar passar é que pointer-events é uma propriedade herdada. Definir pointer-events como none em um pai significa que os filhos também herdam esse valor.
Só que qualquer filho pode sobrescrever o valor herdado, voltando pointer-events para auto (ou outro valor válido).
.parent { pointer-events: none;}
.child { pointer-events: auto;}Neste exemplo, o pai ignora eventos de ponteiro, mas o filho ainda pode se tornar alvo deles.
Um caso de uso comum é um modal. Você pode usar um container de página inteira para centralizar o modal, mas esse container também cobre toda a viewport. Sem mudar o valor de pointer-events dele, ele impede que eventos de ponteiro cheguem aos elementos abaixo.
Definir pointer-events como none no container resolve isso. Mas, como a propriedade é herdada, também é preciso restaurar o próprio modal com pointer-events em auto.
Na demonstração a seguir, quando a propriedade pointer-events está especificada como none, é possível interagir com os botões de fundo mesmo estando eles atrás do overlay.
A propagação de eventos continua funcionando
A propriedade pointer-events só determina qual elemento se torna o alvo do evento. Ela não muda como o evento trafega pelo DOM depois disso.
Por exemplo: se um filho com pointer-events: auto é clicado dentro de um pai com pointer-events: none, o filho ainda se torna o event.target. A partir dali, o evento segue as fases normais de captura e bubbling, então os listeners anexados ao pai continuam rodando.
Em outras palavras, pointer-events afeta a seleção do alvo, não a propagação do evento.
Na demonstração a seguir, dá para ver como o pai com pointer-events: none ainda pode receber click, pointerenter e pointerleave quando você clica ou move o ponteiro para dentro ou para fora do filho interativo.
Ela não desabilita um elemento
A propriedade pointer-events só impede que o elemento se torne alvo de eventos de ponteiro. Portanto, o elemento ainda pode receber foco de teclado com a tecla Tab, e o usuário pode continuar interagindo com ele pelo teclado, se ele for focável por outros meios.
Se você precisa desabilitar um controle de formulário nativo, use o atributo disabled. E, se o objetivo é tornar uma seção inteira da página completamente não interativa (incluindo entrada por ponteiro, foco de teclado e a árvore de acessibilidade), o atributo inert é a melhor escolha.
Essa distinção importa: esconder algo do mouse sem esconder do teclado é uma armadilha clássica de acessibilidade em CSS.
Ela não impede a seleção de texto
Definir a propriedade pointer-events como none não impede que o usuário selecione texto. Ele ainda pode selecioná-lo pressionando Ctrl/Cmd + A no teclado, por exemplo.
Isso acontece porque a seleção de texto não é determinada por um elemento poder ou não se tornar alvo de eventos de ponteiro.
Se o objetivo é impedir que o texto seja selecionado, use a propriedade user-select.
.avoid-user-selection { user-select: none;}Tente selecionar o texto de cada bloco abaixo:
Demonstração
Na construção de um menu de navegação, um padrão comum é esconder um submenu definindo a opacity dele em 0 e depois torná-lo visível quando o usuário passa o mouse sobre o item pai. O problema é que o submenu continua ali, então ele ainda pode receber eventos de ponteiro mesmo sem estar visível.
Abaixo, dá para ver dois menus idênticos. Um esconde o submenu usando apenas opacidade, e o outro usa também pointer-events. Passe o mouse sobre a área do submenu invisível e tente interagir com o conteúdo atrás dela, para ver como a pointer-events evita que elementos invisíveis fiquem no caminho.
Também para entender melhor como cada valor de SVG dessa propriedade funciona, escolha um deles no dropdown e mova o ponteiro pelo anel: sobre a faixa preenchida, dentro do centro vazado e sobre os cantos vazios da bounding box tracejada. Note como a área interativa muda a cada valor.
Suporte dos navegadores
Os valores auto e none funcionam em todos os navegadores em uso, incluindo versões bem antigas. Os valores exclusivos de SVG têm suporte irregular, com o bounding-box sendo o mais recente e o menos difundido. Vale conferir a tabela de suporte no Can I Use antes de depender de um valor específico de SVG.
Propriedades relacionadas
A parceira mais próxima é a user-select, que resolve o problema que a pointer-events não resolve: controlar a seleção de texto. E, para casos de menu, vale ver as 10 dicas para menus responsivos.