English 中文(简体)
How to highlight HTML text without wrapping it with tags?
原标题:

Is it possible to highlight text in an HTML document using without wrapping it with <span> or any other tag for that matter?

For example, in the HTML code <p>The quick fox</p> I would like to highlight quick but without adding a DOM element around it. Adding a DOM element to a parent element is fine.

Thanks!

问题回答

No, it is not possible in a portable manner across all browsers.

You can t tell the browser to render a piece of text differently without inherently changing the DOM, regardless of whether you do it statically or dynamically (with Javascript, for example, as a post processing step).

Edit: In Chrome starting around 2019, you can use Scroll To Text Fragment, but this is not an HTML or browser standard feature.

It is possible if you use an absolutely positioned element with a transparent repeating background image or a transparent background color (using rgba or hsla) and position it over the selected area.

Another way to do it would be to have an absolutely positioned canvas element without a background that takes up the whole browser viewport and draw a transparent rectangle over the selection.

It s not possible.

If you just want no tags in the original source code, it might be possible by adding tags later using Javascript magic. You could do something like

<p highlight="quick">The quick fox</p>

and write a JQuery/Prototype/plain JS function to highlight it on the fly, but what for and why? If you elaborate a bit, someone may come up with an idea.

The only way to do this than I can imagine would be to use the <canvas> element, and render absolutely everything by hand.

There are now multiple ways of achieving this effect without modifying the element structure of the DOM.

They all, however, come with their own caveats.

This answer is derived from research I performed for my open source browser extension Mark My Search (repository), which highlights text you search for on webpages. The natural destructiveness of the accepted approach led to my consideration of many alternatives. The extension will only use one the below approaches if the advanced option "Use CLASSIC highlighting" is unchecked, which is not default due to the disadvantages I am about to describe.

All of my approaches below only involve adding additional painting to the DOM, so there is no option to style text or otherwise change existing content. However, they are entirely non-destructive operations which can result in efficiency gains, making them a competitive alternative.

Important: The assumption through this answer is that you either apply styling directly to elements, or use a stylesheet and generated attributes to apply it remotely. This type of DOM manipulation is still required.

Approaches

  1. Monolithic

    • Overlay the entire content area with a single element.

    • Draw all highlighting onto the element.

      • Get client rects of the required ranges of text.
      • Compare with the client rects of the overall element, obtaining the relative drawn text positions.*
      • Use one of the implementations below.

    Pros:

    • Simple, obvious.
    • All highlighting managed in one place.
    • Efficient for mutations of many elements at once.

    Cons:

    • Many compromises. If you choose to overlay the highlights, opacity of highlighting is necessarily a compromise between visibility and obscuring text. If you underlay, you must remove all backgrounds to avoid highlights being hidden.
    • Inefficient for mutations of few elements, as everything must be recalculated at once (partially mitigated by caching).
    • Inefficient for implementations that perform best in small, disparate frames.
  2. Composite

    • For all text to be highlighted, look at the lowest-level distinct elements which contain parts of the text ranges.

    • Draw highlighting onto each of these elements.

      • Get client rects of the required ranges of text.
      • Compare with the client rects of the specific containing element, obtaining the relative drawn text positions.*
      • Apply one of the implementations below to the containing element.

    Pros:

    • Removes problem of highlights being hidden by element backgrounds.
    • Layout shifts will to an extent carry highlighting with them, reducing the need for vigilant updates/recalculations.
    • Much more pertinent to underlay instead of overlay, so less compromise between obscuring text and emphasising it.
    • Efficient for updates of few elements, as highlighting is modular and decomposed into a range of distinct areas.

    Cons:

    • Complex, nuanced.
    • Under some implementations, one background (normally background-image) is still potentially lost per highlighted element.
    • Inefficient for mutations of many elements at once
    • Inefficient for implementations that perform best in large, few frames.
  3. Hybrid

    • Combine highlighting responsibility into a few elements (for example, ones with display: block to handle highlights for its display: inline children).

Implementations

  1. Elements

    • Create highlighting elements of appropriate sizes.
    • Absolutely position them such that they cover the intended areas.

    Pros:

    • Faultless browser support.
    • Infinite effects are available.

    Cons:

    • Heavyweight, slow, DOM-reliant.
    • Adds many superfluous elements to the main structure of the page, disruptive.
  2. SVG

    • Percent-encode an SVG drawing the laid out highlighting elements.
    • Use url() on the background-image of the ancestor element.

    Pros:

    • Pretty fast.
    • Compatible with modern browsers.

    Cons:

    • Page CSPs will (rarely) block the use of url(), expecting it to extract remote content.
  3. Canvas

    • Percent-encode a canvas drawing the laid out highlighting elements, or use a <canvas> element.
    • Use url() on the background-image of the ancestor element.

    Pros:

    • Compatible with modern browsers.

    Cons:

    • Extremely slow after only a few canvases (especially large ones), presumably due to each pixel being explicitly painted. Seems to be poorly optimised, particularly for transparent pixels.
    • If url() is used: Page CSPs will (rarely) block the use of url(), expecting it to extract remote content.
  4. Houdini

    • Register a Paint worklet that draws highlights based on sizing and positioning CSS variables, with whatever additional info you deem necessary (see details of Houdini Paint API).
    • Use background-image: paint({worklet name}) as appropriate on elements to display highlighting.
    • Define CSS variables (the ones consumed by the worklet) on the same element - consider using a stringified JSON object for this which will be unpacked within the worklet, it s surprisingly efficient.
  5. element()

    • Create highlighting elements of appropriate sizes.
    • Absolutely position them such that they cover the intended areas, in a dedicated portion of the DOM (offscreen).
    • Use background: element({ID of highlighting element}) as appropriate on elements to display highlighting.

    Pros:

    • Infinite effects are possible.
    • Much more viable than the direct DOM alternative.

    Cons:

    • Specific to Firefox, on which it is experimental but has been supported for years.
    • For some reason requires application to background instead of just background-image, resulting in more overriding of element backgrounds. This seems to be an oversight.
    • Heavyweight, a little slow, DOM-reliant.

Dynamically Updating

I won t go into much detail about this, as it is very specific to your needs. However, to obtain fully up-to-date highlighting when applied to an entire page, I needed:

  • A MutationObserver observing subtree, childList, and characterData for the document body, in order to detect all changes that may affect matching. My case is very extreme, which is why I must observe the entire document; I optimised using various methods, including filtering out events that did not require attention.

  • A ResizeObserver observing highlighted elements currently in view, in order to recalculate highlighting when layout shifts occur.

  • An IntersectionObserver observing all highlighted elements for when they appear in the viewport, in order to draw highlighting and the ResizeObserver only when needed. This is an optimisation measure only.

Information

Here is the PR in which I achieved this, using multiple of the above methods which could be swapped out. I used a highly structured approach - involving caching across the DOM and other optimisations, such as decomposing it into multiple stages - to make it efficient even for cases where all of an average page has been highlighted in various colours. An overview is presented in the PR.

This being one of the most extreme possible cases, it should be entirely possible for others to achieve good results without significant performance loss.

I am happy to answer any questions regarding my implementation, or getting started with these technologies.

Articles

Notes

*Due to convoluted browser behaviour when it comes to the association of client rects with actual layout+position, it is very difficult to make sure an overlay-based highlighting algorithm will position highlight-boxes correctly in all cases. I have still not managed to correctly account for the effect of border (which disrupts calculations) or strange cases of flow content, but it is technically possible using only the results of Range.getClientRects() and Element.getClientRects().





相关问题
CSS working only in Firefox

I am trying to create a search text-field like on the Apple website. The HTML looks like this: <div class="frm-search"> <div> <input class="btn" type="image" src="http://www....

image changed but appears the same in browser

I m writing a php script to crop an image. The script overwrites the old image with the new one, but when I reload the page (which is supposed to pickup the new image) I still see the old one. ...

Firefox background image horizontal centering oddity

I am building some basic HTML code for a CMS. One of the page-related options in the CMS is "background image" and "stretch page width / height to background image width / height." so that with large ...

Separator line in ASP.NET

I d like to add a simple separator line in an aspx web form. Does anyone know how? It sounds easy enough, but still I can t manage to find how to do it.. 10x!

热门标签