【问题标题】:How to apply rounded borders to highlight/selection如何应用圆角边框突出/选择
【发布时间】:2014-09-19 01:36:46
【问题描述】:

我在一个项目中使用Visual Studio Online 有一段时间了,他们在其在线代码查看器中将圆形边框应用于选择的方式非常有趣:

我尝试检查元素并寻找某种自定义 CSS,但没有运气。

我觉得这需要一些复杂的“hacks”才能使其工作,但这似乎很有趣,因为我以前从未见过它。

他们如何为选区应用圆角边框?

注意:正常选择在选择时完全隐藏,圆角选择就像常规选择一样跟随您的光标。不是在你选择了一些东西之后。

编辑:我有@Coma 的答案created a fork 应该在 Firefox 中工作,如果使用鼠标移动时选择:

$(document).on('mousemove', function () {

(在某些情况下边框仍然可以使用。)

【问题讨论】:

  • 反对者介意解释?
  • 抱歉我的第一个评论,误解了你的评论,没有看到是你写的。也就是说,我投了赞成票。我也很好奇他们是怎么做到的!
  • 删除了反对票。但无法帮助您解决问题。
  • 我之前已经在浏览器中实现了自定义选择,与包装编辑器元素本身相比,突出显示更有可能是通过覆盖完成的。
  • 嘿@TimDown !!!,我正在使用你的 Rangy 库制作一个 jsfiddle!

标签: css html visual-studio selection


【解决方案1】:

CSS'::selection 仅支持声明颜色、背景、光标和轮廓(See W3C)。所以不可能为纯 CSS 的选择定义border-radius

所以我相信他们是像 cmets 中提到的 Niklas 那样做的:

  1. 等到用户选择某些内容(selectstart、mousedown 和 mouseup 的组合)
  2. 获取选中的文本
  3. 获取所选文本的位置(从开头开始的字符数),因为如果您只是双击单个单词,则无法从中创建规则
  4. 用 div 或 span 包裹所选内容
  5. 将样式应用于包装器
  6. 听用户点击其他内容等(取消选择文本)-> 删除包装器

我开始尝试自己创建解决方案,但由于花费了太多时间,我失去了动力。 也许有人需要我的建议(我使用 jQuery):

对于第 2 点:

var selection = (window.getSelection() // > IE 9 
                 || document.selection.createRange() //< IE 9
                ).toString();

对于第 4 点,使用 replace()

对于第 6 点:

$(".selection").replaceWith($(".selection")[0].childNodes);

Fiddle

【讨论】:

    【解决方案2】:

    我可以向您保证,这与 html、css 边框半径或突出显示无关。证据?

    1. 整个选择显示为具有多个边和顶点的单个块,并且不对称。如果不使用 SVG 或 Canvas,则无法直接在 html 中拥有多个边缘形状。 (嗯,这是一个可供讨论的可能性)
    2. 如果不是单个块,而是多行突出显示或用某种 HTML 或 CSS 或 JS 标记,则不能有这样的向外曲线:

      (总有可能。例如,您可以使用带有边框半径的白色矩形来覆盖选择,但这似乎效率非常低且不太可能......所以......)

    总结,他们必须使用 Canvas 属性和大量代码来“覆盖”交互式选择过程。编辑器中出现了许多不同类型的突出显示,例如“同字突出显示”、“选定突出显示”、“失焦突出显示”等......为了使所有这些有效地发生,我找不到更好的选择比画布。

    不要因为我发这个而生气。但我不想将我 4 小时的研究视为浪费。至少我得到了一个观察结果,就是这样。

    更新:

    虽然我认为使用末尾带有边框半径的白色矩形覆盖选择,是一种相当低效且不必要的方式。微软不这么认为。

    他们使用弯曲边缘的矩形来覆盖高光的末端以产生这种效果。他们使用绝对定位的圆边&lt;div&gt;s 来提供突出显示的效果。在&lt;div&gt; 的末尾,它们覆盖了一个圆角矩形的图像。

    感谢他们,他们在这方面做得很好。

    【讨论】:

    • canvas/SVG 技术实际上听起来很有趣,可以实现。
    【解决方案3】:

    他们实际上是使用圆边矩形来覆盖句子中比前面或后面的行更小的高光结尾(正如我在第 2 点中所说的那样)。自己检查一下:

    1. 您不能直接从 iframe 检查元素。所以点击其他地方并导航到 iframe。我是使用 chromes 的内置源代码检查器完成的。
    2. 然后使用此图像找出图像中突出显示的线条的位置。
    3. &lt;div&gt; 包含所有“选择”亮点。他们只是在文本下方放置圆边、背景色的矩形,使用 绝对,顶部和左侧!!!**
    4. 下一个&lt;div&gt;拥有类似背景色的&lt;div&gt;s,只是它们用于突出重点词、相似词等...

    这实际上是 iframe 的内容。看到顶部的#document了吗?

    查看扩展视图。上面有代码的小空间实际上是突出显示的部分。

    但这对于一个简单的网站来说并不是一个好主意。他们确实需要对单词和字母进行解析和填充,因为它应该是一个高端的代码编辑器,所以不能怪他们花费相对较少的时间来“圆”一点边缘。

    【讨论】:

    • @Cyral 这是一个很棒的方法。他们使用monotype字体。因此,他们知道每个字符的确切高度和宽度,并且必须在字符之前或之后开始“突出显示”
      ,以更接近“mouseDown()”的为准……智能工作…… !! :)
    【解决方案4】:

    不完美,但它正在工作:

    http://jsfiddle.net/coma/9p2CT/

    删除真正的选择

    ::selection {
       background-color: transparent;
    }
    

    添加一些样式

    span.highlight {
        background: #ADD6FF;
    }
    
    span.begin {
        border-top-left-radius: 5px;
        border-bottom-left-radius: 5px;
    }
    
    span.end {
        border-top-right-radius: 5px;
        border-bottom-right-radius: 5px;
    }
    
    pre.merge-end > span:last-child {
        border-bottom-right-radius: 0;
    }
    
    pre.merge-end + pre > span:last-child {
        border-top-right-radius: 0;
    }
    
    pre.merge-begin > span:first-child {
        border-bottom-left-radius: 0;
    }
    
    pre.merge-begin + pre > span:first-child {
        border-top-left-radius: 0;
    }
    

    将每个字符包装在节点元素中

    var format = function () {
    
        var before = -1;
        var html = $.trim(editor.text())
        .split("\n")
        .reverse()
        .map(function (line) {
    
            var a = line.length === before ? 'merge-end' : '';
            before = line.length;
    
            return '<pre class="' + a + '"><span>' + line.split('').join('</span><span>') + '</span></pre>';
        })
        .reverse()
        .join('');
    
        editor.html(html);
    };
    

    获取选中的节点并突出显示,照顾他们的父母

    var getSelectedNodes = function () {
    
        var i;
        var nodes = [];
        var selection = rangy.getSelection();
    
        for (i = 0; i < selection.rangeCount; ++i) {
    
            selection
            .getRangeAt(i)
            .getNodes()
            .forEach(function (node) {
    
                if ($(node).is('span')) {
    
                    nodes.push(node);
                }
            });
        }
    
        return nodes;
    };
    
    var highlight = function (nodes, beforeNode) {
    
        var currentNode = $(nodes.shift()).addClass('highlight');
        var currentParent = currentNode.parent();
    
        if (beforeNode) {
    
            var beforeParent = beforeNode.parent();
    
            if (currentParent.get(0) !== beforeParent.get(0)) {
    
                currentNode.addClass('begin');
                beforeNode.addClass('end');
                beforeParent.addClass('merge-begin');
            }
    
        } else {
    
            currentNode.addClass('begin');
        }
    
        if (nodes.length) {
    
            highlight(nodes, currentNode);
    
        } else {
    
            currentNode.addClass('end');
        }
    };
    
    format();
    
    $(document).on('mouseup', function () {
    
        $('.highlight').removeClass('highlight begin end');
        highlight(getSelectedNodes());
    });
    

    感谢Tim Down Rangy

    【讨论】:

    • +1,最近。确保您记住 Firefox 用户的 moz-selection :)
    • 认真的吗?每个字符都有一个&lt;span&gt;
    • 使用mousemove 代替mouseup 有什么缺点吗?它似乎使这项工作完美无缺,因为它会在您移动鼠标时立即应用选择,而不是在您停止选择时应用。
    • 是的,mousemove 是正确的,但我不确定使用如此多的 span 元素是否会因为如此快速地处理而变得昂贵。顺便说一句,我正在研究另一种使用画布的方法,但它今天还没有准备好(我必须工作)。
    • 哦,谢谢!但是@Cyral,我认为使用画布(我正在玩Paper.js)并映射形状(因为高度是已知的)我们可以获得更好的解决方案。准备好后我会发布它,忙碌的一周!
    【解决方案5】:

    我也喜欢您可能喜欢的解决方案。它基本上适用于每个单词周围的跨度,然后您可以应用边界半径。但我不知道如何归档上面的角落 - 所以它只是水平连接的。

    p.introduction {
      width: 150px;
    }
    
    p.introduction span {
      background-color: #f48024;
      color: #1d1d1e;
      border-radius: 25px;
      float: left;
      padding: 0 15px 0 10px;
      margin: 4px -15px 4px 0px;
    }
    &lt;p class="introduction"&gt;&lt;span&gt;Be&lt;/span&gt;&lt;span&gt;part&lt;/span&gt;&lt;span&gt;of&lt;/span&gt;&lt;span&gt;our&lt;/span&gt;&lt;span&gt;awesome&lt;/span&gt;&lt;span&gt;community&lt;/span&gt;&lt;span&gt;and&lt;/span&gt;&lt;span&gt;have&lt;/span&gt;&lt;span&gt;fun&lt;/span&gt;&lt;span&gt;with&lt;/span&gt;&lt;span&gt;us.&lt;/span&gt;&lt;/p&gt;

    【讨论】:

      猜你喜欢
      • 2013-10-26
      • 2010-09-24
      • 1970-01-01
      • 2022-12-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-12-20
      • 1970-01-01
      相关资源
      最近更新 更多