Design,Tutoriais -
Destacando um Elemento HTML (coachmark): Efeito Spotlight ( com CSS3 e Javascript puro)
Obs. Se você só quer o código pronto, pule para o final do post. Ou acesse o link do JSFiddle.
As vezes precisamos encontrar formas de destacar elementos na tela (coachmark). Isso é muito útil principalmente quando você está tratando de pequenos tutoriais, afim de ajudar os usuários. Convém, também, entregar soluções simples e esteticamente elegantes para que ajudem no relacionamento com a ferramenta.
Faz algum tempo, um cliente meu quis criar um modo tutorial em seu sistema. Esse tutorial não deveria permitir que outras áreas da tela fossem clicadas até que a pessoa confirmasse que compreendeu. Como designer, lembrei que, anos atrás, no Android, a Google usava uma espécie de spotlight, mas não vi nada a respeito para websites. E, também, eu precisava que fosse dinâmico. Então eu resolvi usar meus conhecimentos de CSS3 e Javascript para usar essa ideia. E é disso que eu falarei neste tutorial.
Apesar de eu ter usado originalmente jQuery, para compartilhar com todos, resolvi fazer uma versão com Javascript puro, de forma que você poderá adicionar a qualquer aplicação web que você já tenha.
Criando a Estrutura: HTML e o CSS3
Para criar o efeito, vamos usar uma propriedade interessante do CSS3 chamada clip-path. O clip-path permite que criemos elementos vetoriais que serão usados como máscaras. Já utilizamos essa propriedade em um outro exemplo, no caso, sobre um loader.
Exemplo de uso do clip-path:
Dessa forma, se já não tiver, teu projeto deve possuir um container principal que é pai de todos os elementos, mas abaixo do <body>. Se não houver, o crie, é até uma questão lógica de organização para evitar problemas futuros. Veja um código de exemplo:
xxxxxxxxxx
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body data-rsssl=1>
<div id="container" class="container">
</div>
</body>
</html>
A div container vai ser justamente o elemento que iremos clippar. Para ajudar em nosso exemplo, vamos criar um form básico dentro do container, ficando assim:
xxxxxxxxxx
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body data-rsssl=1>
<div id="container" class="container">
<div class="form">
First name:<br>
<input type="text" name="firstname" id="firstname" value="Mickey">
<br> <br>
Last name:
<br>
<input type="text" name="lastname" id="lastname" value="Mouse">
<br><br>
<input type="submit" id="submeter" value="Submit">
<div class="btn_ajuda">?</div>
</div>
</div>
</body>
</html>
Para finalizar nosso HTML, vamos colocar a caixa de mensagens. Repare que no código abaixo a caixa de mensagem vai ter uma div chamada spacer. O objetivo dessa div vai ser adicionar o espaço do elemento referência, para que o código funcione também em dispositivos móveis e ela deverá ficar fora do container da aplicação. Mais à frente isso vai ficar mais bem explicado.
x
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body data-rsssl=1>
<div id="container" class="container">
<div class="form">
First name:<br>
<input type="text" name="firstname" id="firstname" value="Mickey">
<br> <br>
Last name:
<br>
<input type="text" name="lastname" id="lastname" value="Mouse">
<br><br>
<input type="submit" id="submeter" value="Submit">
<div class="btn_ajuda">?</div>
</div>
</div>
<!-- Mensagem de Ajuda-->
<div class="mensagem_area" id="mensagemAjuda">
<div class="spacer"></div>
<div class="mensagem">
<h2></h2>
<p></p>
<button onclick="ocultarAjuda()">
OK, entendi
</button>
</div>
</div>
</body>
</html>
Agora que o HTML está pronto, vamos para o CSS inicial. A primeira fase é estabelecer todo comportamento da div que estamos usando como container. Também precisamos adicionar uma cor ao plano de fundo, que vai ser a cor que usaremos como base para a área em lowlight.
A animação ficará a cargo do recurso transition do CSS3. Importante ressaltar que uma animação criada por CSS é mais leve e possui melhor frequência do que uma criada pelo Javascript. Isso porque o navegador tenta usar a renderização da GPU nesses casos. Dessa forma, vamos aplicar o parâmetro transition para aplicar o efeito.
xxxxxxxxxx
body{
margin: 0;
font-family: sans-serif;
background-color: #15d115;
}
.container{
background-color: white;
min-width: 100%;
/* Obs. A largura do clip-path, abaixo, está definido
como 3840 de diâmetro, porque ultrapassa
o tamanho do 4K - O clip-path considera o raio.
Posteriormente, você poderá trabalhar com
adição de classes, se você quiser evitar
a definição inicial desse tamanho,
mas é necessário haver uma para poder
ativar a animação.*/
clip-path: circle(1920px at center);
clip-path: circle(1920px at center);
transition: 2s ease-in-out;
transition: 1s ease-in-out;
position: absolute;
min-width: 100%;
min-height: 100%;
}
O parâmetro position como absolute, com suas larguras e alturas mínimas marcados como 100% servirão para emular o comportamento do body. Isso só é necessário porque alguns sistemas costumam ter áreas menores do que a primeira dobra do navegador. Nesse caso, apenas, é necessário aplicar esses três parâmetros.
Já para o CSS do bloco de mensagem, você pode fazer algo do jeito que preferir. Apenas é importante lembrar que esse bloco deverá ficar com position absolute, ou fixed, dependendo de como for sua aplicação, para que possa se encaixar no local correto.
xxxxxxxxxx
.mensagem_area{
position: fixed;
opacity: 0;
pointer-events: none;
transition: 2s ease-in-out;
transition: 1s ease-in-out;
color: white;
display: flex;
justify-content: flex-start;
flex-wrap: wrap;
}
.mensagem_area.show{
opacity: 1;
max-width: 100%;
pointer-events: all;
}
.mensagem_area .spacer{
visibility: hidden;
}
.mensagem_area .mensagem{
width: 250px;
padding: 15px;
box-sizing: border-box;
}
.mensagem_area .mensagem h2{
font-size: 18px;
font-weight: bold;
margin: 0;
}
.mensagem_area .mensagem p{
font-size: 16px;
}
Criando as Funções Javascript
Agora basta que a gente crie as funções de aparecer e desaparecer o spotlight. Originalmente eu havia usado jQuery, pois ele possui soluções rápidas e funcionais como o offset nativo e outerWidth, mas com uma pesquisa rápida conseguir adaptar, apesar do código ter ficado um pouquinho maior.
O código consiste em 4 blocos:
- Capturar largura e posição em relação ao document, do objeto referência (que será passado como parâmetro), fazendo os cálculos apropriados para adição do círculo. Você irá reparar que é usado como base o raio e não o diâmetro, pois é a referência do parâmetro clip-path;
- Adicionar o clip ao container;
- Adicionar os textos da mensagem a partir dos parâmetros passados;
- Aplicar os estilos com os novos parâmetros. O timeout que precede a adição da classe show da mensagem existe para que o texto apareça após a transição do spotlight.
xxxxxxxxxx
function mostrarAjuda(id_obj, titulo, mensagem){
//Pegar raio e posição
var raio = document.querySelector('#' + id_obj).offsetWidth / 2;
var offset = document.querySelector('#' + id_obj).getBoundingClientRect();
offset.top = offset.top + document.body.scrollTop;
offset.left = offset.left + document.body.scrollLeft;
//Adicionar clip
var clip = "circle(" + parseInt(raio).toString() + "px at " + parseInt(offset.left + raio).toString() + "px " + parseInt(offset.top + offset.height/2).toString() + "px)";
var container = document.querySelector('#container');
container.style.clipPath = clip;
container.style.webkitClipPath = clip;
//Textos
document.querySelector("#mensagemAjuda h2").innerHTML = titulo;
document.querySelector("#mensagemAjuda p").innerHTML = mensagem;
//Estilos
document.querySelector("#mensagemAjuda .spacer").style.width = parseInt(raio * 2 + offset.left).toString() + "px";
document.querySelector("#mensagemAjuda .spacer").style.height = parseInt(raio).toString() + "px";
document.querySelector("#mensagemAjuda").style.top = parseInt(offset.top).toString() + "px";
setTimeout(function(){
document.querySelector("#mensagemAjuda").classList.add("show");
}, 1500);
}
Por fim, basta adicionar uma função que restaure as configurações originais dos estilos e textos.
xxxxxxxxxx
function ocultarAjuda(){
//Limpar
document.querySelector("#mensagemAjuda").classList.remove("show");
container.style.clipPath = "circle(1920px at center)";
container.style.webkitClipPath = "circle(1920px at center)";
setTimeout(function(){
document.querySelector("#mensagemAjuda h2").innerHTML = "";
document.querySelector("#mensagemAjuda p").innerHTML = "";
}, 2000);
}
Como sempre, deixei o código completo para você testar ou copiar. No caso, o código está no jsfiddle e você pode visualizar abaixo:
Se você gostou da publicação, curta e compartilhe esta página com o maior número de pessoas. Aproveite e curta nossa página do Facebook.
ATUALIZAÇÃO: Que tal experimentar uma versão com blur, usando o html2canvas? Obs. É meio pesado. Dê preferência a usar em projetos para desktop.