Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support type-dependent search result highlighting via CSS #12474

Open
wants to merge 3 commits into
base: master
Choose a base branch
from

Conversation

timhoffm
Copy link
Contributor

@timhoffm timhoffm commented Jun 24, 2024

Edit: Summary

This adds result type-dependent HTML classes to the <li> elements of the search result list. Implemented types / classes are:

  • index: If the search term is found in an index such as the glossary
  • object: If the search term a code object such as a python function
  • text: If the search term is found in plain documentation text
  • title: If the search term is found in a heading

The basic style intentionally does not apply styling to these classes to not interfere with derived themes. We encourage theme authors to apply suitable styling to the results list via CSS as they see fit. Check sphinx13.css in this PR as an example.


It's helpful to visually distinguish different content types.

This PR adds itemType to the javascript result entries (one of "title", "index", "object", "text" - please check that these names make sense, I've inferred them from the JS context) and adds them as a class to the <li> item in the result list. This allows styling via CSS.

For simplicity, I've styled with unicode symbols, which should give a decent look without the need to ship our own symbols. Derived themes have the ability to adapt this via CSSand use their own icons if they want to.

Before / after:

image         image

@jayaddison jayaddison added type:enhancement enhance or introduce a new feature type:proposal a feature suggestion html search labels Jun 24, 2024
background-image: url(file.png);
background-repeat: no-repeat;
background-position: 0 7px;
list-style: "\25A1"; /* Unicode: White Square */
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder whether it might make sense to be slightly more explicit and define these using the CSS list-style-type property?

Also, to check: is the white-square default here intended to highlight cases where sites have upgraded their Sphinx CSS but not rebuilt their searchindex.js?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not a CSS expert. I was anticipating that list-style is easier to override for downstream themes, e.g. list-style: url(image.svg), but just a guess. If you say list-style-type is better, I'm happy to change.

I've added the empty square as a catch-all fallback; e.g. could be that somebody rewrites search and includes a new type, but forgets the corresponding CSS. Likely other things can happen and the empty square as as placeholder is better than nothing.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not a CSS expert. I was anticipating that list-style is easier to override for downstream themes, e.g. list-style: url(image.svg), but just a guess. If you say list-style-type is better, I'm happy to change.

Me neither, and your intuition may be correct. I based my suggestion on a sense that list-style-type is slightly less ambiguous (list-style does accept the same values, but can also be set to an image URL), and also a small note on the Mozilla MDN page:

The list-style property is specified as one, two, or three values in any order. If list-style-type and list-style-image are both set, the list-style-type is used as a fallback if the image is unavailable.

I've added the empty square as a catch-all fallback; e.g. could be that somebody rewrites search and includes a new type, but forgets the corresponding CSS. Likely other things can happen and the empty square as as placeholder is better than nothing.

That makes sense. A concern I have with it is that the same (or a similar) symbol is used on some systems when a unicode codepage/symbol is not found in the relevant font, and that could make problems slightly trickier to track down. Perhaps we could set the value to initial (initial browser default)?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A concern I have with it is that the same (or a similar) symbol is used on some systems when a unicode codepage/symbol is not found in the relevant font

Our assumptions in the HTML search is that the user has a modern browser, and hence we should be confident in using Unicode -- every modern browser is able to display emoji, etc.

Comment on lines 122 to 124
ul.search li.title {
list-style: "\1F4C1"; /* Unicode: File Folder */
}
Copy link
Contributor

@jayaddison jayaddison Jun 24, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the only annotation symbol that I find slightly confusing / out of context, personally.

It does sorta logically fit that it's for use to represent that titles are 'containers' in some sense for text content.

I'm browsing unicode character references to try to find something else that could represent text/documents, headings/titles, and/or the potential for containership/nesting.

Edit: remove repetitive phrasing

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe it's a controversial misuse, but perhaps the paragraph symbol (called Pilcrow, as I learned today)?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(or we could try to bring the capitulum back into style)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Another alternative could simply be to style title and text matches identically to begin with.

I'll try to spend a bit more time thinking about this before adding any further thoughts/comments.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The idea behind folder was "structuring element" but I'm not too convinced of it either.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On reflection: I'd recommend keeping this simple, and using the same styling for both title and text search results - that is, 1F4C4 (unicode: page facing).

We could still emit the CSS classes title and text in the result list, allowing downstream sites to customize their display to suit their projects if they choose.

Some reasoning for this suggestion: with a default Sphinx configuration and HTML build, it is possible to infer from each listed search result whether the input search query term(s) matched in the corresponding document's title and/or content body. In my personal opinion it is a nice addition to be able to distinguish between glossary items and programming objects, but seems lower priority to distinguish page title matches from other page content matches.

@jayaddison

This comment was marked as resolved.

@jayaddison
Copy link
Contributor

Maybe nitpicky: the horizontal margin/padding between the icons and the search result titles has increased; is there a way to reduce that back to near the original spacing?

@wlach
Copy link
Contributor

wlach commented Jun 25, 2024

Might be interesting to see how this works with some popular themes e.g. furo, readthedocs, and sphinx-book-theme. I suspect it'll look fine but can't hurt to double check.

@timhoffm
Copy link
Contributor Author

Maybe nitpicky: the horizontal margin/padding between the icons and the search result titles has increased; is there a way to reduce that back to near the original spacing?

Done:

image

@timhoffm
Copy link
Contributor Author

timhoffm commented Jun 25, 2024

Might be interesting to see how this works with some popular themes e.g. furo, readthedocs, and sphinx-book-theme. I suspect it'll look fine but can't hurt to double check.

Good point. They all set ul.search {list-style: none}, which this ul.search li.* {list-style: ...} will superseed; e.g. Furo:
image

That may be ok, but still we're pushing unexpected styling, and e.g. the spacing is too narrow for furo.
If we do that, we should give them a heads up. They can either set ul.search li {list-style: none} themselves. or maybe the also want to style depending on the type.

The alternative would be only to implement the class now, and change the CSS later, which gives downstream more time to react.

@timhoffm
Copy link
Contributor Author

timhoffm commented Jun 27, 2024

Alternative idea:

  • Remove any styling from the basic theme, so that it's a simple bulleted list (the current constant background image does not add much and it feels reasonable to keep basic theme styling minimal).
  • Still add the html classes in basic via search
  • Actual CSS styling is up to the downstream themes; in particular I would add the styling proposed to sphinx13 and alabaster. Other themes should decide for themselves.

What do you think?

@jayaddison
Copy link
Contributor

If we roll the theming out 'centrally' (in the basic) theme, I'd expect that there could be some display/layout issues for some downstream themes; hopefully those problems would be reported back to us and we could resolve them in a cross-theme-compatible manner (but those are assumptions!).

If we roll out only the HTML class names, my guess is that many themes will not notice or react to the possibility to style these elements -- that's fine, but I do think that there is a genuine user-facing improvement possible here. I also think that there's some risk -- but also some opportunity -- if fragmentation of result icon theming occurs.

In either scenario I'd be hopeful for some future requests for additional class names / tweaks to improve the categories further.

I don't have a strong preference either way yet; just trying to consider the likely outcomes at the moment.

One other thought: the basic.css_t file is a Jinja template, and can contain some basic logic; we could theoretically add a Sphinx HTML search config option to control the theming. I don't know whether that's worth it (another config setting to support, potentially over a long timescale), but again mentioning it so that we can consider it.

@timhoffm
Copy link
Contributor Author

From the themes listed at https://sphinx-themes.org/, I pulled the GitHub stars as a proxy measure of usage. ~10 themes cover most of the user space.

image

So the amount of impact is managable either way: If we supply icons by default, we can check them. If we only provide classes, we can notify them that they could do styling.

From the top 7 themes only Alabaster and Bootstrap keep the original search result styling. The others have chosen to explicitly style the result themselves (often just using list-style: none).

Conceptually, I find it attractive to include as little styling as possible in the basic theme. It should give the structure, appearance should be handled by the derived themes. Us putting icons into basic makes it potentially harder for them. I believe my proposal above minimizes negative impact.

@jayaddison
Copy link
Contributor

@timhoffm Thanks for providing that contextual data. I'm mostly in agreement with your suggestion about leaving the basic theme as-is - providing a gradual opt-in approach seems sensible.

An aspect I'm puzzling over is whether we should be even more cautious about affecting downstream, and not remove the file.png icon alongside each result (redundant though it does seem).

Yet one more thought: the choice of tag names does seem important, as you highlighted originally. In particular object currently strikes me as an area where we might be able to do better -- perhaps passing the Sphinx domain and object-type (e.g. py:module, c:function) could allow additional useful theming.

@jayaddison
Copy link
Contributor

An aspect I'm puzzling over is whether we should be even more cautious about affecting downstream, and not remove the file.png icon alongside each result (redundant though it does seem).

I think that was too cautious and hesistant/change-resistant of me. I'm not an accessibility expert but I would expect that the file.png icon appearances in the result HTML are noise that people may want to filter out; we should remove the icon since it doesn't add any value visually either, IMO.

@timhoffm timhoffm force-pushed the search-icons branch 3 times, most recently from b4affb1 to 0ac6880 Compare June 30, 2024 15:49
@timhoffm
Copy link
Contributor Author

timhoffm commented Jun 30, 2024

I've changed the basic theme to not have any styling. The effect can be seen as follows at the example of alabaster, which uses the default settings for search:

old / new:

grafik grafik

The sphinx13 theme still got the icon styling. I plan to provide a PR for that on alabaster as well, once this PR is merged.

Yet one more thought: the choice of tag names does seem important, as you highlighted originally. In particular object currently strikes me as an area where we might be able to do better -- perhaps passing the Sphinx domain and object-type (e.g. py:module, c:function) could allow additional useful theming.

IMHO we anyway need object to allow easy styling for the whole category. We don't want downstream themes to force adding a long exhaustive list in CSS .py:module .py:class .c:function ... { }. For simplicity, I've now started only with object. One can later expand this to have more specific py:module etc. classes alongside object.

@jayaddison
Copy link
Contributor

The sphinx13 theme still got the icon styling. I plan to provide a PR for that on alabaster as well, once this PR is merged.

+1 to this approach (applying the change to the project's own documentation theme first / milling our own grain)

Copy link
Contributor

@jayaddison jayaddison left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good to me - thanks @timhoffm!

image

@jayaddison
Copy link
Contributor

Ah, one more thing @timhoffm - I always forget this - please could you add an entry to the CHANGES.rst file to describe this feature?

@timhoffm timhoffm changed the title ENH: Show type-dependent icons on search result entries ENH: Support type-dependent search result highlighting via CSS Jul 1, 2024
@timhoffm
Copy link
Contributor Author

timhoffm commented Jul 1, 2024

It seems the changelog entries only refer to the PR number and reflect it's title. I've put a short summary at the top to make this more useful. Possibly worth adding a section on CSS classes in HTML theme development at some point. But that's for later.

@AA-Turner AA-Turner changed the title ENH: Support type-dependent search result highlighting via CSS Support type-dependent search result highlighting via CSS Jul 2, 2024
This allows styling different types of results individually.
It's helpful to visually distinguish different content types.

This PR adds `itemType` to the javascript result entries
(one of "title", "index", "object", "text") and adds
them as a class to the <li> item in the result list.
This allows styling via CSS.

The basic theme only contains the mechanism to add the HTML
classes. It does intentionally not do any styling via CSS.
We reserve that freedom to derived themes.

For the internal sphinx13 theme, I've styled with unicode
symbols, which should give a decent look without the need
to ship our own symbols.
Copy link
Contributor

@wlach wlach left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry a bit late looking at this again.

Approving because I wouldn't be sad if this went in as-is. We'll need a committer (maybe @picnixz or @chrisjsewell?) to actually accept + land it though.

One thing I wonder is whether we should add some documentation about this feature, perhaps somewhere like this:

https://www.sphinx-doc.org/en/master/development/html_themes/index.html

We could also link maintainers of other themes to this as a resource, to get them to adopt/use this new data.


let listItem = document.createElement("li");
listItem.classList.add(resultType)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you add a quick comment explaining what this does?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you mean a comment here for clarification, or a code comment for documentation?

Starting here: The search results are written to HTML <li> elements - in JS here the listItem variable. resultType is one of the strings "title", "object", "index", "text". This code line adds the result type as class attribute. e.g. resulting in <li class="title">, which can then be in a CSS selector for styling.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, something like that but I would probably be a little more succinct: // Add a class representing the item's type: can be used by a theme's CSS selector for styling or so.

@timhoffm
Copy link
Contributor Author

timhoffm commented Jul 9, 2024

One thing I wonder is whether we should add some documentation about this feature, perhaps somewhere like this:

https://www.sphinx-doc.org/en/master/development/html_themes/index.html

We could also link maintainers of other themes to this as a resource, to get them to adopt/use this new data.

Both yes, but only makes sense, when the exact semantics and behavior is agreed upon (c.f. #12474 (comment))

@AA-Turner
Copy link
Member

Remove any styling from the basic theme, so that it's a simple bulleted list (the current constant background image does not add much and it feels reasonable to keep basic theme styling minimal).

I'd prefer to add this to the built-in themes if possible, including basic. Though Sphinx13/Alabaster can be fancier with their styling if need be.
Traditional, EPUB, Agogo, and Nonav will also need to be updated.

Once done, we can alert the maintainers of downstream themes.

Other than that, looks great currently! Thanks @timhoffm, @wlach, @jayaddison, et al.

A

@timhoffm
Copy link
Contributor Author

timhoffm commented Jul 11, 2024

from above:

Conceptually, I find it attractive to include as little styling as possible in the basic theme. It should give the structure. Appearance should be handled by the derived themes. Us putting icons into basic makes it potentially harder for them.

Any styling we do in basic may have to be undone by downstream theme authors, which is cumbersome and potentially fragile if we change something in the basic styling later. The current basic styling with the static document image does not convey information. It's just a stylistic thing (whether looking nicer or just adding clutter is in the eye of the beholder). From a usability perspective, a plain bullet list is as good as the bullet list with the static document icon. Given that it's just styling and the potential downstream problems, IMHO basic should not have any styling.

Note - as mentionend in the above post - that a majority of themes have just removed our styling (using list-style: none). So no styling seems to be not a bad default.

+1 on adding styling back in for the builtin themes. Should this be in this PR or can that be a follow-up?

@AA-Turner
Copy link
Member

AA-Turner commented Jul 11, 2024

Given that it's just styling and the potential downstream problems, IMHO basic should not have any styling.

basic should provide a sane and useful set of defaults. I spoke in favour of adding the styles to basic as it would mean that every downstream theme gets those defaults automatically. For the themes that customise their list styles (with list-style: none or otherwise), surely that would override basic?

+1 on adding styling back in for the builtin themes. Should this be in this PR or can that be a follow-up?

Whichever you prefer. The changes to Alabaster will need to be in a PR as it lives at https://github.com/sphinx-doc/alabaster.

A

@timhoffm
Copy link
Contributor Author

timhoffm commented Jul 11, 2024

basic should provide a sane and useful set of defaults.

I claim that the sane and useful set of defaults is no styling when taking into account compatibility with existing downstream themes 😃.

You could consider the changes discussed here as a multi-step process:

  1. Only add the HTML class but do not change styling.
  2. Remove the current static document icon from basic.
  3. Add new more fancy styling to basic.

(1.) Is 100% backward compatible.
I vouche that (2.) does not have a relevant negative impact on downstream themes. Either they have removed the document icon themselves, in which case nothing has changed, or they have kept the original style, in which case they just don't get the document icon in the future. The difference is shown in #12474 (comment). I propose that this should be acceptable. It's a minor visual change, and I assume it's unlikely that theme authors have a strong opinion on the icon being there - they likely just have taken what is provided.
(3.) Was my initial propsal, but I withdraw from that, because it is far more likely to interfer with downstream themes that customize the search results. See for example #12474 (comment). It's not just a simple on/off switch but alsco involves placement / spacing aspects that need to be handled depending on the customized theme.

Personally, I think going up to including (2.) is an ok migration. I don't dare to (3.) because of potentially breaking other themes. - If you want to do that, I recommend to check the effect on the most important ones, but that's cumbersome and I'm not going to do that. If you otherwise think (2.) is not a good middle ground, I'd rather only go to (1.) and not touch default styling at all.

This is my personal recommendation. You should go as far as you think is feasible. But if it's 3., please take over from here. I intentionally stepped back from this.

@timhoffm
Copy link
Contributor Author

Whichever you prefer. The changes to Alabaster will need to be in a PR as it lives at https://github.com/sphinx-doc/alabaster.

I'd rather go to separate PRs so that we frist have a definitive version of this PR fixed.

@AA-Turner
Copy link
Member

You make a fair argument -- lets go with (2) for now, and I will see if I have time to evaluate (3) later -- but that won't block this or any follow-up PRs to the built-in themes. Thank you for humouring the discussion!

A

// Add a class representing the item's type:
// can be used by a theme's CSS selector for styling
// See SearchResultKind for the class names.
listItem.classList.add(`result-kind-${resultKind}`);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@AA-Turner in #12542 we don't seem to add any prefixes to domain/object-type when those are added as CSS classes. What's the reason for adding a prefix here?

It feels to me like the CSS class names we choose here could be long-lived; this is the only part of the branch as-is that I feel cautious about.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I had originally not included any prefix, because the typical selector will be ul.search li.[type] and ul.search li.object seemed clear enough. But I don’t have a strong opinion.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Gradually iterating through some thoughts:

  • From the perspective of a theme author, the ability to reference consistent CSS names when styling search results and ToC entries seems like it'd be beneficial.
  • Sphinx-style object qualifiers (py:module, cpp:class) would conflict with CSS syntax - so class="py module" or class="cpp class" might be the preferred output here.
  • Building upon those two thoughts, the kind value that we're talking about here is useful context -- but it is a different dimension to the Sphinx object qualifier. The values could conflict for some domains though -- so in fact, a prefix does seem like a good idea.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One more thought: for some reason I don't love the word kind in this context. It seems like an unnecessarily-different synonym for type -- itself a frequently-overused name in software.

I'd like to express something about what the currently-named-kind here relates to. And I think it's something like a match category -- it's how and/or why the search algorithm decided to include an entry (yes, that's generally derived 1-1 from how the search index is structured, but it doesn't necessarily have to be).

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Prototyping / pseudogenerating some results:

<result class="match-object cpp class">utils::Format</result>
<result class="match-text">Formatting Guidelines</result>
<result class="match-object py function">foo.bar.format</result>

Does that seem semantic and themeable?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(I'm not suggesting that we include Sphinx domain and object type yet -- but trying to anticipate that they could be included in future)

Copy link
Contributor Author

@timhoffm timhoffm Jul 13, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

class="py module" seems a good extension possibility. I’ve first thought about class="py-module" because you likely want to be domain-specific and not style all modules the same way across contexts. However, you can easily combine selectors .py.module, which is not worse than .py-module and leaves more flexibility.

I’m not having a good prefix either. Personal thoughts: type is very generic. Same with kind, but that’s additionally feels somewhat unconventional. match connects too much to the search process and less to the result. Other possibilities context, category

Not necessarily related but possibly a good way to come up with suitable names(prefix and type/kind): If we’d add a GitHub-like filter mechanism to the search field, what would be intuitive names for our end users? e.g. some_func category:api feels better thansome_func kind:object.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not necessarily related but possibly a good way to come up with suitable names(prefix and type/kind): If we’d add a GitHub-like filter mechanism to the search field, what would be intuitive names for our end users? e.g. some_func category:api feels better thansome_func kind:object.

Mm, good question - query language syntax. The label:value syntax does seem well established for various web-based search engines. For that specific example, I think that name:some_func might be simplest - the function is an object entity that is indexed, and those entities tend to have names. Other entities could be document, section, word... but I'd also be wary of reinventing the docutils node hierarchy.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It feels to me like the CSS class names we choose here could be long-lived; this is the only part of the branch as-is that I feel cautious about.

I had originally not included any prefix, because the typical selector will be ul.search li.[type] and ul.search li.object seemed clear enough.

I added a prefix out of caution -- CSS backwards-compatibility is very annoying, as you've no idea what selectors people can use. Whilst ul.search li.[type] is best, li.[type] or even .[type] is possible, and hence reusing the class names somewhere else carries a small risk. Namespacing with some prefix reduces that. I haven't merged #12542 as I'm unsure if the benefit is worth the long-term backward compatibilty commitment. On the other hand, I might be overthinking this whole endevaour entirely.

One more thought: for some reason I don't love the word kind in this context. It seems like an unnecessarily-different synonym for type -- itself a frequently-overused name in software.

type felt wrong here, though on a 'feelings' level rather than a great deal of rationality. No strong feelings on going back to type really.

A

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
html search type:enhancement enhance or introduce a new feature type:proposal a feature suggestion
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants