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

[ENH] Custom CSS Styling for Site/Theme/Page/Module #4314

Closed
thabaum opened this issue Jun 5, 2024 · 12 comments
Closed

[ENH] Custom CSS Styling for Site/Theme/Page/Module #4314

thabaum opened this issue Jun 5, 2024 · 12 comments

Comments

@thabaum
Copy link
Contributor

thabaum commented Jun 5, 2024

Enhancement Proposal: Custom CSS Styling for Theme/Site/Page/Module/Module Instance

Description

Enable users to add custom CSS styling for Theme, Site, Page, or Module in Oqtane Framework. Custom styles can be added via an input field for each level, and the load order should execute after the respective Theme/Site/Page/Module is loaded.

Including Theme as an option could allow for instance-wide custom theme CSS managed via the themes control panel area, providing flexibility in customization.

Integration with Radzen Based HTML/Text V2 Editor

The upcoming Proof of Concept (POC) for the new Radzen based HTML/Text V2 editor could incorporate syntax color display, facilitating easier creation of custom styles. Alternatively, another package with similar capabilities could be considered.

Implementation Details

  • Custom CSS input would be stored in the database to allow for dynamic customization without the need for application restarts.
  • The input would be inserted into a wrapped <style></style> element and injected in the CSS styles load order, executing after the CSS of the respective Theme/Site/Page/Module, if the custom CSS field is not empty.
  • Proper input validation, output encoding, and sanitization would be implemented to mitigate security risks associated with storing dynamic CSS in the database.
  • Additional features could include the ability to edit CSS files directly, with an option to restart the application if needed, providing flexibility for advanced users.

Pros and Cons

Saving Custom CSS to the Database:

Pros:

  • Dynamic customization without touching the file system.
  • Controlled access managed through user roles and permissions.
  • Easy updates without deploying new files or restarting the application.
  • Seamless integration with other aspects of the application's data model.

Cons:

  • Potential performance overhead depending on implementation.
  • Increased complexity in managing dynamic CSS.
  • Security risks if not properly sanitized.

Adding a New File in the Website:

Pros:

  • Improved performance by serving static files.
  • Simplicity in adding new files without complex database interactions.
  • Caching benefits for improved performance.
  • Version control for tracking and managing CSS changes.

Cons:

  • Maintenance challenges with managing multiple CSS files.
  • Deployment complexities requiring application restarts.
  • Less granular access control compared to database-managed CSS.

Additional Considerations

Wrapping CSS content within <style></style> tags helps ensure proper rendering but doesn't enhance the security of the CSS content itself. Proper input sanitization, output encoding, and implementation of Content Security Policy (CSP) are essential to mitigate security risks, including HTML injection and Cross-Site Scripting (XSS) vulnerabilities.

@sbwalker
Copy link
Member

@thabaum just to clarify... the HTML4 and HTML5 specifications do not technically support <style> elements in the body of an HTML document - they only support them in the head. That being said, many browsers do handle <style> elements in the body - but this approach would not pass any HTML validator. The enhancement proposal is focused on "CSS styling" but does not specify if the expectation is that these styles should be injected in the head, body, or both. The reason why this is important is because the implementation may need to be different depending on where the elements are injected.

@sbwalker
Copy link
Member

sbwalker commented Jun 11, 2024

Oqtane already supports Head Content and Body Content at both the Site level and Page level:

image

<style> elements specified as Head Content will be injected into the head of the page. <style> elements specified as Body Content are not currently injected because they are not valid based on the HTML specification ( Body Content only supports <script> elements).

@thabaum
Copy link
Contributor Author

thabaum commented Jun 11, 2024

@sbwalker I tried at the page level to use Head Content and at the Site level adding the <style> elements but nothing was being applied, like it was being removed if I recall.

Pretty much this would work but does not give an easy CSS styling field to enter in related. In DNN there was a "Custom CSS" for sites I felt could be applied at Theme/Site/Page/Module levels with some type of editor in a way that was very obvious this is where you would do this type of styling customization's.

@thabaum
Copy link
Contributor Author

thabaum commented Jun 11, 2024

And to clarify, it should really go in the Head section, I am forcing it in the body section using the RAW Html Editor currently.

@sbwalker
Copy link
Member

sbwalker commented Jun 11, 2024

@thabaum the Site/Page Head Content should be injecting the <style> information - perhaps there is a bug in the logic which parses the field to extract the scripts (which need to be processed in a different way due to Blazor's script handling).

@sbwalker
Copy link
Member

@thabaum I have confirmed that this ThemeBuilder.razor method does not handle <style> tags:

    private string AddHeadContent(string headcontent, string content)
    {
        if (!string.IsNullOrEmpty(content))
        {
            // format head content, remove scripts, and filter duplicate elements
            content = content.Replace("\n", "");
            var index = content.IndexOf("<");
            while (index >= 0)
            {
                var element = content.Substring(index, content.IndexOf(">", index) - index + 1);
                if (!string.IsNullOrEmpty(element) && (PageState.RenderMode == RenderModes.Static || (!element.ToLower().StartsWith("<script") && !element.ToLower().StartsWith("</script"))))
                {
                    if (!headcontent.Contains(element))
                    {
                        headcontent += element + "\n";
                    }
                }
                index = content.IndexOf("<", index + 1);
            }
        }
        return headcontent;
    }

It only handles meta and link tags (and scripts).

Parsing HTML is problematic... this approach will likely need to be revisited in the future.

@thabaum
Copy link
Contributor Author

thabaum commented Jun 11, 2024

@sbwalker Thanks for reviewing this further. Not a top priority but would be nice to keep as something close to the burner for when the time can allow. 🚀

@sbwalker
Copy link
Member

@thabaum I believe #4435 resolves this issue for Site and Page HeadContent - you should be able to include <style> elements which are injected into the page.

@sbwalker
Copy link
Member

@thabaum please test the Head Content capability to include style elements in the 5.2.0 release - I believe it addresses most of the items described in this issue.

@thabaum
Copy link
Contributor Author

thabaum commented Jul 28, 2024

@sbwalker I will take a look at it hopefully tomorrow if I can't find some time today. Thanks!

@thabaum
Copy link
Contributor Author

thabaum commented Aug 7, 2024

@sbwalker the <style> element in the Head Content area works as expected now in both Page and Site.

I tested the load order and it seems to work OK as I put red color for site and blue color for page without !important being included and the pages rendered with the colors properly (only the page set to blue color had blue text the rest had red)

I wish we could do this via module level as well as discussed in this enhancement request to further elaborate.

I think a setting for the "Themes" and "Modules" and be in their respected management admin section for global custom styling of all instances and per instance (the theme at site level does this already, but module per instance and globally does not as there is no option to add head or body content like for site/page). I believe this would be a 1 up for enhancing theming capabilities if I am making sense.

Thanks for making this work for us as now I can theme the entire site while working on creating themes without editing files or each page individually without update the theme source :) This makes custom sites and pages so much easier going forward 👍

@sbwalker
Copy link
Member

@thabaum after further investigation, adding HeadContent/PageContent support at the Module level has a lot of complications and side effects so I am not going to approve it at this time. If style elements need to be overridden for a module it is currently possible to include these at the Page level - so that is the recommended approach for now.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants