Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

css text ::selection with round corners

I saw this selection in VSCode and monaco-editor and it looks really good :

enter image description here

SO I tried to recreate this, here is my effort :

#ta{
  font-size : 18px;
}
#ta::selection{
  background : rgba(173, 216, 130, 0.9);
  border : 1px solid transparent;
  border-radius : 15px;
}
<textarea id="ta"></textarea>

But this doesn't get the round corners effect(I hope you get it) like the one shown in the picture.

Please help me out. Answers appreciated.

like image 915
Pranav Avatar asked Jan 01 '20 15:01

Pranav


2 Answers

As some people already commented on your question

::selection is only a very small subset of CSS rules that can be applied to it, border-radius not being one of them...

So, next step is, if you really need it, how could you go around it? One of the options is: You could use the "selected" string and then add some HTML tags. Then when you select text and release the mouse all your CSS styles will be applied.

Keep in mind: this might not work in "normal" text boxes

I hope the following code gives you an example to get started

var selectionElements = document.querySelectorAll('.selection');
selectionElements.forEach(function(element){
    element.setAttribute('original-content', element.innerHTML);  // this will be needed to reset to original after a selection has been made
    element.addEventListener('mouseup', function() {
        replaceContentWithSelectionWrapper(this)
    });
});

function replaceContentWithSelectionWrapper(element) {
    let selection = window.getSelection().toString();
    if(selection.length <= 0) { // if selection length is not bigger then 0 we can stop right here
        return;
    }
    // next lines should be self explanatory
    // get start of string until selection
    // get the end of string after selection
    // concatenate all strings back together
    let selObj = window.getSelection(); 
    let selRange = selObj.getRangeAt(0);
    let originalString = element.innerHTML;
    let start = originalString.substr(0, selRange.startOffset);
    let end = originalString.substr(selRange.endOffset);
    element.innerHTML = start + '<span class="mark-special-selected">' + selection + '</span>' + end;
    document.body.classList.add('selections-enabled');
}

function clearSelections() {
    var selections = document.querySelectorAll('[original-content]');
    selections.forEach(function(selection){
        selection.innerHTML = selection.getAttribute('original-content');
    });
}

document.body.addEventListener('mousedown', function(){
    if(document.body.classList.contains('selections-enabled')) {
        document.body.classList.remove('selections-enabled');
        clearSelections();
    }
});
.selection {
  font-size : 18px;
}
.mark-special-selected,
.selection::selection{
  background : rgba(173, 216, 130, 0.9);
  border : 1px solid transparent;
  border-radius : 15px;
  outline: 2px;
}
<h1 class="selection">Here is some text, you can select some of it with your mouse</h1>
<p class="selection">Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.</p>
like image 111
caramba Avatar answered Nov 14 '22 08:11

caramba


With this CSS, the effect is more like the text selection of VS Code, it's just not instantly rounded and it doesn't have the effect on each intersection (and has a line of one pixel blank between lines, due to the lack of a border), but the text won't move when selecting it.

I remind that the text selection of Visual Studio Code looks like this:

Visual Studio Code text selection

Other issues with the code snippet below:

  • If the click is released outside of the text box, the rounded corners effect may not work;
  • If the text is selected from outside the text box, the selection will be the default one;
  • In this example, if the cursor selects the header text and releases the click on the text bellow, the upper selected text is written lower, and the effect is only on the lower paragraph;
  • In this example, if the cursor selects the lower text and releases the click on the upper text, the lower selected text is written upper, and the effect works only on the selected copied part which is now in the header text;
  • If the text is selected too fast (I think this is the cause of it), the rounded corners don't work on the header text.

Anyway, strange things are going on with this text selection, and if someone can handle them, it would be great.

var selectionElements = document.querySelectorAll('.selection');
selectionElements.forEach(function(element){
    element.setAttribute('original-content', element.innerHTML);  // this will be needed to reset to original after a selection has been made
    element.addEventListener('mouseup', function() {
        replaceContentWithSelectionWrapper(this)
    });
});

function replaceContentWithSelectionWrapper(element) {
    let selection = window.getSelection().toString();
    if(selection.length <= 0) { // if selection length is not bigger then 0 we can stop right here
        return;
    }
    // next lines should be self explanatory
    // get start of string until selection
    // get the end of string after selection
    // concatenate all strings back together
    let selObj = window.getSelection(); 
    let selRange = selObj.getRangeAt(0);
    let originalString = element.innerHTML;
    let start = originalString.substr(0, selRange.startOffset);
    let end = originalString.substr(selRange.endOffset);
    element.innerHTML = start + '<span class="mark-special-selected">' + selection + '</span>' + end;
    document.body.classList.add('selections-enabled');
}

function clearSelections() {
    var selections = document.querySelectorAll('[original-content]');
    selections.forEach(function(selection){
        selection.innerHTML = selection.getAttribute('original-content');
    });
}

document.body.addEventListener('mousedown', function(){
    if(document.body.classList.contains('selections-enabled')) {
        document.body.classList.remove('selections-enabled');
        clearSelections();
    }
});
.selection {
  font-size: 18px;
}
.mark-special-selected, .selection::selection{
  background: #8884;
  border-radius: 4px;
}
<h1 class="selection">Here is some text, you can select some of it with your mouse</h1>
<p class="selection">Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.</p>
like image 36
BarryCap Avatar answered Nov 14 '22 09:11

BarryCap