Haga clic, arrastre, suelte: acaba de seleccionar un texto en una página web, probablemente para copiarlo y pegarlo en algún lugar o para compartirlo. ¿No sería genial si al seleccionar ese texto se revelaran algunas opciones que facilitan esas tareas? Eso es lo que hace un menú de selección.
Es posible que ya esté familiarizado con los menús de selección si alguna vez ha utilizado un editor en línea. Cuando selecciona texto, las opciones para dar formato a la selección pueden flotar sobre él. De hecho, estoy escribiendo este borrador en un editor que hace exactamente esto.
Veamos cómo podemos crear un menú de selección como este usando la API de selección de JavaScript. La API nos da acceso al espacio y contenido del área seleccionada en una página web. De esta forma podemos colocar el menú de selección exactamente arriba el texto seleccionado y obtenga acceso al texto seleccionado en sí.
Aquí hay un fragmento de HTML con un texto de muestra:
<article>
<h1>Select over the text below</h1>
<p>Cascading Style Sheets (CSS) is a style sheet language used for describing the presentation of a document written in a markup language such as HTML. CSS is a cornerstone technology of the World Wide Web, alongside HTML and JavaScript. CSS is designed to enable the separation of presentation and content, including layout, colors, and fonts. This separation can improve content accessibility, provide more flexibility and control in the specification of presentation characteristics. </p>
</article>
<template><span id="control"></span></template>
Hay una <template>
etiqueta al final allí. El <span>
dentro está nuestro control de menú de selección. Cualquier cosa dentro de un <template>
la etiqueta es no renderizado en la página hasta que luego se agregue a la página con JavaScript. Agregaremos el control del menú de selección a la página cuando el usuario seleccione texto. Y cuando el usuario selecciona ese texto, nuestro menú de selección le pedirá que lo twittee.
Aquí está el CSS para darle estilo:
#control {
background-image: url("data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 width="40px" height="40px"><foreignObject width="40px" height="40px"><div xmlns="http://www.w3.org/1999/xhtml" style="width:40px;height:40px;line-height:40px;text-align:center;color:transparent;text-shadow: 0 0 yellow, 2px 4px black, -1px -1px black;font-size:35px;">💬</div></foreignObject></svg>");
cursor: pointer;
position: absolute;
width: 40px;
height: 40px;
}
#control::before{
background-color: black;
color: white;
content: " tweet this! ";
display: block;
font-weight: bold;
margin-left: 37px;
margin-top: 6px;
padding: 2px;
width: max-content;
height: 20px;
}
Consulte este artículo para saber cómo utilicé un emoji (💬) para la imagen de fondo.
Hasta ahora, el texto de muestra está listo y se ha modificado el estilo del control del menú de selección. Pasemos al JavaScript. Cuando se realiza una selección, obtendremos el tamaño y la posición del área seleccionada en la página. Luego usamos esas medidas para asignar la posición del control del menú de selección en la parte superior central del área seleccionada.
var control = document.importNode(document.querySelector('template').content, true).childNodes[0];
document.querySelector('p').onpointerup = () => {
let selection = document.getSelection(), text = selection.toString();
if (text !== "") {
let rect = selection.getRangeAt(0).getBoundingClientRect();
control.style.top = `calc(${rect.top}px - 48px)`;
control.style.left = `calc(${rect.left}px + calc(${rect.width}px / 2) - 40px)`;
control['text']= text;
document.body.appendChild(control);
}
}
En este código, primero obtenemos una copia del control del menú de selección dentro <template>
, luego asígnelo al control
variable.
A continuación, escribimos la función de controlador para el onpointerup
evento del elemento que lleva el texto de muestra. Dentro de la función, obtenemos la selección y la cadena seleccionada usando document.getSelection()
. Si la cadena seleccionada es no vacío, luego obtenemos el tamaño y la posición del área seleccionada, a través de getBoundingClientRect()
y colóquelo en el rect
variable.
Utilizando rect
, calculamos y asignamos el top
y left
posiciones de la control
. De esta forma, el control del menú de selección se coloca un poco por encima del área seleccionada y se centra horizontalmente. También estamos asignando la cadena seleccionada a una propiedad definida por el usuario de control
. Esto luego se usará para compartir el texto.
Y, finalmente, agregamos control
a la página web usando appendChild()
. En este punto, si seleccionamos parte del texto de muestra en la página, el control del menú de selección aparecerá en la pantalla.
Ahora podemos codificar lo que sucede cuando se hace clic en el control del menú de selección. En otras palabras, lo haremos de modo que el texto se tuitee cuando se haga clic en el mensaje.
control.addEventListener('pointerdown', oncontroldown, true);
function oncontroldown(event) {
window.open(`https://twitter.com/intent/tweet?text=${this.text}`)
this.remove();
document.getSelection().removeAllRanges();
event.stopPropagation();
}
Cuando se hace clic en el control, se abre una pestaña con la página “Nuevo Tweet” de Twitter, completa con el texto seleccionado listo para funcionar.
Después del mensaje del tweet, el control del menú de selección ya no es necesario y se elimina, junto con cualquier selección realizada en la página. La forma en que el pointerdown
las cascadas de eventos más abajo en el árbol DOM también se detienen en este punto.
También necesitamos un controlador de eventos para onpointerdown
evento de la página:
document.onpointerdown = ()=> {
let control = document.querySelector('#control');
if (control !== null) {control.remove();document.getSelection().removeAllRanges();}
}
Ahora, el control y cualquier selección realizada en la página se eliminan al hacer clic en cualquier lugar de la página excepto en el control del menú de selección.
Manifestación
Aquí hay una versión más bonita que creó Chris:
Y aquí hay un ejemplo que muestra más de un control en el menú de selección:
Sobre esa
No es totalmente necesario que lo usemos. En su lugar, también puede intentar simplemente ocultar y mostrar el control de alguna otra manera, como el hidden
Atributo HTML o CSS display
. También puede crear un control de menú de selección en el propio JavaScript. Las opciones de codificación dependerán de la eficiencia con la que las ejecute y sus alternativas, si es necesario, así como de cómo encajan con su aplicación.
Algunos consejos de UI / UX
Si bien este es un efecto agradable, hay un par de cosas a considerar al usarlo para garantizar una buena experiencia de usuario. Por ejemplo, evite inyectar su propio texto en la selección de texto, ya sabe, como agregar un enlace a su sitio en el tweet generado automáticamente. Es intrusivo y molesto. Si hay alguna razón para hacerlo, como agregar la cita de la fuente, permita que el usuario vea una vista previa del texto final antes de publicarlo. De lo contrario, el usuario podría confundirse o sorprenderse con la adición.
Una cosa más: es mejor si el control del menú está fuera del camino. No queremos que cubra demasiado el contenido circundante. Ese tipo de cosas se suma a la “pérdida de datos” de CSS y queremos evitarlo.
En pocas palabras: comprenda por qué sus usuarios necesitan seleccionar texto en su sitio web y agregar los controles de una manera que se salga del camino de lo que están tratando de hacer.