Problem/Motivation

When the off-canvas tray dialog is moved from this module and made available to any module it needs to at least:

  1. Have a consistent appearance whenever it is used,
  2. Style every component that an admin theme styles so that module developers won't have to write additional CSS.
  3. Style every component so that it is responsive to the width of the tray as if it were the viewport.
  4. Be implemented so that it's CSS is isolated from the front-end theme

And at best:

  1. Allow module developers to apply *any* theme to the tray.
  2. Provide a separate form-mode out-of-the-box for forms in the tray.

The tray will likely be used in two main modes.

  1. Regular mode: No special treatment needed, and
  2. Admin mode: Should a have consistent look.

This issue deals with admin mode.
#2847522: Allow off-canvas links to be rendered by either "default" or "admin" renderer will allow these 2 modes. It can be assumed whatever solution we come up for a consistent theming will only be implement in "admin" mode.

Proposed resolution

This issue is to discuss possible solutions. Actual patches will be posted on related issues

Current Ideas:

CSS Reset

#2826722: Add a 'fence' around settings tray with aggressive CSS reset. Currently this adds a CSS reset file but could be expanded to load off_canvas_admin_stylesheet CSS files from the current admin theme similar to QuickEdit. See quickedit_library_info_alter()

There is also this issue: #2632584: Add a "public admin" theme subtype so that admin themes can have subthemes for front-end UI components, that moves all of the outside-in CSS into a sub-theme of Seven.

IFrame

#2853222: Explore using an IFrame to sandbox CSS for the Off Canvas tray
Loading the dialog content in an iFrame will totally element front-end theme CSS from effecting the content. This would require not using the standard method for making dialog links which include a 'use-ajax' class and data-dialog-type attribute. The dialog would probably not use Ajax at all because it would just need to load a iFrame element with the src element using the href of the link.

The iFrame method would probably introduce other problems that we can discuss here.

Control presentation with Javascript

This option would involve using js to either:

  1. Remove the core classes and replace them with classes from the off-canvas library.
  2. Prefix classes from a theme with a class specific to the tray.
  3. Maintain the css for the tray in the javascript file and inject it dynamically (least attractive option)
  4. Pre-render tray forms with css from the admin theme, aggregate the css and inline it, then cache the forms

Option 2 would not be a fail-safe solution because a front-end theme may still style any combination of elements or data attributes in a way that is more specific than the off-canvas classes, and since the front end theme loads last it already has the upper hand in the war of specificity. Option 4 is better because inline css always wins out but the process would have a lot of overhead and require phantom.js as well as a css inliner library like https://github.com/drdk/dr-css-inliner.

Shadow DOM oe shadow DOM polyfill

It has been suggested that we use the shadow DOM or a polyfill of the shadow DOM. This is not an option right now since the browser coverage is not there yet, but it's worthy of note in case it comes up in further discussion, or if this issue outlives the browser coverage issue. :)

Other solutions????

Remaining tasks

  1. Discuss pro and cons of each method
  2. Try out each method in related issues
  3. Choose a method

User interface changes

?

API changes

?

Data model changes

Probably none

Comments

tedbow created an issue. See original summary.

tedbow’s picture

tkoleary’s picture

Issue summary: View changes
tkoleary’s picture

Issue summary: View changes
tkoleary’s picture

Issue summary: View changes
tkoleary’s picture

Issue summary: View changes
tkoleary’s picture

Issue summary: View changes
tkoleary’s picture

Issue summary: View changes
tkoleary’s picture

Issue summary: View changes
tkoleary’s picture

Issue summary: View changes
tkoleary’s picture

Issue summary: View changes
tkoleary’s picture

Issue summary: View changes
tedbow’s picture

Issue summary: View changes

Move section in summary that deals with 2 modes as that should probably be available regardless of the solution we determine for this issue.

Also wanted to point out that if someone was making a new contrib or custom theme it would be extremely easy(though maybe cumbersome) to make absolutely sure that none of the front end CSS rules affect the tray.

Since outside-in-page-wrapper.html.twig uses the class "dialog-offcanvas__main-canvas" to surround the main canvas(everything that is not the tray a theme could simply prefix every single CSS rule with .dialog-offcanvas__main-canvas

Assuming though that #2847522: Allow off-canvas links to be rendered by either "default" or "admin" renderer is committed this would also stop the rules from being applied to the Off-Canvas tray when it is not in admin mode and doesn't have admin CSS applied.

In that case maybe it would be better to apply a class off-canvas-admin to the tray when it is used as in admin mode.
Then all style rules in front-end themes could be written as

:not(.off-canvas-admin) .other-selectors {
 ....
}

Obviously this would be asking a lot of theme developers but I think it is possible to make a system where CSS isolation would be possible without using an iFrame or shadow-dom. We could still provide the CSS reset and make that was enough to make the tray theme correctly in all core themes.

tkoleary’s picture

Issue summary: View changes
tkoleary’s picture

Obviously this would be asking a lot of theme developers

Not really. Most are using preprocessors anyway so, for example your Scss would be:

:not(.off-canvas-admin) {
  .other-class-1 {
    attribute: value;
  .other-class-2 {
    attribute: value;
  }
}

Which would compile to:

:not(.off-canvas-admin) .other-class-1 {
  attribute: value;
}
:not(.off-canvas-admin).other-class-2 {
  attribute: value;
}

But that still does put some burden on the themer. They should not need to worry about this.

We could gain one rung in the ladder of specificity by prefixing (the tray css) with the id instead of the class. It goes against general best practices but in this case, where there is not likely to ba anything further down the cascade from the tray I think it might be warranted.

ksenzee’s picture

This is a lot like the Drupal Gardens themebuilder. In fact, it's almost exactly like the themebuilder. We explored most of these options for that project, and ended up with an aggressive CSS reset plus an ID-based specific prefix for all the styles we actually wanted. That would be my recommendation here as well. It was practically bulletproof, and a lot easier to maintain than an iframe- or JS-based solution would have been.

CatherineOmega’s picture

an aggressive CSS reset plus an ID-based specific prefix for all the styles we actually wanted.

That's a good idea; the off-canvas tray looks great on my theme, but just adding some greater specificity would cover our bases for themes that risked overriding them. I don't think it's necessary to deal with anything more aggressively than that. Besides, there are always going to be theme builders who WANT to override those styles. I've personally had a good dozen clients who would be freaked out if it looked like it didn't "fit" their branding.

tkoleary’s picture

Besides, there are always going to be theme builders who WANT to override those styles. I've personally had a good dozen clients who would be freaked out if it looked like it didn't "fit" their branding.

Yes, but we should be clearly documenting that those users (who want to theme the tray) use theme override in the .info file. That should not impact how we write the css.

tedbow’s picture

I am leaning towards the CSS reset method over the IFrame or any other method.

It seems like to make a viable and flex solution it will need to:

  1. Provide a decent look at out-of-the-box without requiring theme support. There are already a lot of sites out there using different default themes.
  2. Do as much possible to prevent the current theme CSS from bleeding into theme. Probably with a method like @ksenzee suggested in #16
  3. Provide documentation for theme builders to explain how to make sure their CSS doesn't affect the tray. Maybe something like #15
  4. Provide a method for individual themes specify certain CSS files should be loaded when the tray is displayed. This could be done like the QuickEdit module handles this, a theme could specify off_canvas_admin_stylesheets in the *.info file. If written correctly these extra stylesheet could guaranteed to not affect the rest of the site by targeting the offcanvas id or class
  5. Provide a setting on "/admin/appearance" to select Off-Canvas Dialog Theme with the options:
    • Standard - this would load library from the outside_in(later core)
    • Default Theme
    • Admin Theme
    • List all other themes(only themes with the off_canvas_admin_stylesheets would be listed here)
tkoleary’s picture

@tedbow

After looking at this from many angles now I think your summary is correct.

I do also think that the method for styling the tray should follow the quickedit pattern. however there are a few questions we'd still need to answer.

  1. Should these admin styles be scoped only to the offcanvas tray or to a more general class like "admin-front", so that they could be used more broadly for styling other dialogs, the toolbar, etc.? If so we would potentially reduce overall code by only then needing one reset and one set of styles for all 'front end admin" things.
  2. If we are enabling styles to be pulled from a theme is it even necessary to have a default set of style sheets or can we simply move them to the theme and have less code to maintain?

The drawback of #1 is that in order to get the tight scoping we want we may need to duplicate multiple IDs in the CSS eg.

#toolbar .admin-front .myclass
#ui-dialog .admin-front .myclass,
#ui-dialog-offcanvas .admin-front .myclass {
  attribute: value;
}

Unless we could get away with only using the IDs in the reset css which I'm not sure would work. @ksenzee, thoughts?

tedbow’s picture

So looking at my suggestion in #19.3 regarding the way to allow themes to override css for the dialog:

I realized themes can also declare libraries. So why not instead of requiring themes to make a property in their .info.yml "off_canvas_admin_stylesheets" why not just let them declare a library "off_canvas_admin_styles"
Then if the library could also make dependencies. So if theme just wanted to a couple new styles in addition to the Setting Tray's modules styles it could make it's library dependent on the Settings Tray library.

UPDATE:
Would what I sugguest actually work. What if Settings Tray was disable would this cause a failure b/c the library depends on library that is not available or just not load?

tkoleary’s picture

Would what I suggest [won't] actually work. What if Settings Tray was disable[d] would this cause a failure b/c the library depends on library that is not available or [would it] just not load?

If we were to do this the way it's been done for other core components, we'd add base or 'structural' css to Stable, base css with added classes to Classy, and theme or 'skin' css to Bartik and Seven. The assumption of that approach is that you are laying the groundwork for themes to extend and style these components for their front ends.

In this case what I believe the user expects is that the tray is themed by some administrative CSS that comes from outside their front-end theme. In the case of quickedit we made the assumption that the source should be the admin theme, essentailly re-routing it's theme inheritance to the front end through a PHP tunnel. This is great for quickedit, but what I discovered in styling the tray was that, because the tray has some special needs based on it's context just piping in the admin theme is not a great solution. That's why I like the approach of the patch that follows the quickedit pattern, because it enables adding a *sub-theme* for the tray (and/or other fornt-end admin things) whose chain of inheritance flows through the *admin theme* not the front end theme.

That's essentially the value of the approach in #2632584: Add a "public admin" theme subtype so that admin themes can have subthemes for front-end UI components

tedbow’s picture

tedbow’s picture

Status: Active » Fixed

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.

tedbow’s picture

Component: outside_in.module » settings_tray.module

Changing to new settings_tray.module component. @drpal thanks for script help! :)