The Thymeleaf template in Spring Boot does not display the necessary CSS styles

Currently, I am exploring the use of Thymeleaf and Flying Saucer for generating PDFs from templates. However, I have encountered an issue with applying CSS to my Thymeleaf template. Despite reviewing various questions & answers here, here, and here, none of the proposed solutions seem to solve my problem.

This is how my resources folder directory appears:

https://i.sstatic.net/8LOwi.png

I am utilizing the default directories that Spring searches for. The head tag in my template.html looks like this:

<head>
    <title>Spring Boot and Thymeleaf Example</title>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
    <link rel="stylesheet" type="text/css" href="../static/css/style.css" th:href="@{/css/style.css}"/> 
</head>

If I embed my CSS directly into template.html, the resulting PDF file displays proper styling (indicating no issues with the PDF generation process). However, when attempting to link to the CSS file as demonstrated above, the generated PDF lacks proper styling (implying that the CSS is not being applied).

Moreover, I am able to access my CSS file at

http://localhost:8080/css/style.css
, so there seems to be no problem with Spring serving static content.

For clarity, here is how I generate the PDF document:

private final SpringTemplateEngine templateEngine;
private final Log log;

@Autowired
public PdfGenerator(SpringTemplateEngine templateEngine) {
    this.templateEngine = templateEngine;
    log = LogFactory.getLog(getClass());
}

public void generate(HttpServletRequest servletRequest, HttpServletResponse servletResponse, ServletContext servletContext) {
    // Parse the PDF template using Thymeleaf
    Locale locale = getLocale(servletRequest);
    WebContext context = new WebContext(servletRequest, servletResponse, servletContext, locale);
    context.setVariable("user", buildDummyUser());
    context.setVariable("discounts", buildDummyDiscounts());
    String html = templateEngine.process("template", context);

    // Generate the PDF using Flying Saucer
    try (OutputStream outputStream = new FileOutputStream("generated.pdf")) {
        ITextRenderer renderer = new ITextRenderer();
        renderer.setDocumentFromString(html);
        renderer.layout();
        renderer.createPDF(outputStream);
    } catch (IOException | DocumentException e) {
        log.error("Error while generating PDF", e);
    }
}

I opted for WebContext over Context due to encountering the following error with Context:

org.thymeleaf.exceptions.TemplateProcessingException: Link base "/css/style.css" cannot be context relative (/...) unless the context used for executing the engine implements the org.thymeleaf.context.IWebContext interface

My question remains: What am I overlooking here that results in my style.css failing to apply to template.html?

Answer №1

Encountering similar issues, I attempted to utilize the thymeleaf template resolver for PDF generation. After conducting extensive research on thymeleaf and the spring framework, experimenting with WebContext, HttpServletRequest, and various Spring Thymeleaf integration solutions proved futile. It became apparent that the issue was not a syntax error, leading me to resort to using absolute paths instead of relative ones. For more information, refer to this URL.

My assumption stems from the fact that our resources are served on

localhost:8080/myapp/css/style.css
. The relative path to request resources varies depending on its context. For instance, in a typical thymeleaf model Veiw where HTML pages are returned to clients, the context would consist of the request hostname, port, and application context (e.g., localhost:8080/myapp). Consequently, the relative path will be constructed based on this context. In the case of /css/style.css as the relative path, combining the context and relative path results in
localhost:8080/myapp/css/style.css
.

Unlike the web context scenario, wherein offline templates reside on the server backend, the context shifts to the server's running context. Hence, the assumed context would be the local server path + appcontext (e.g., D:/myServer/apps/myapp), rendering the relative path /css/style.css as

D:/myServer/apps/myapp/css/style.css
, which proves impractical. To utilize static resources, providing the absolute path is imperative.

Initially, I resorted to:

<link rel="stylesheet" type="text/css" th:href="@{http://localhost:8080/myapp/css/style.css}"/>

While this solution worked adequately, it posed challenges when dealing with multiple hostnames or servers operating behind proxies. A hardcoded approach could become cumbersome. Therefore, determining the actual base URL that the user requests is crucial, necessitating the use of HttpServletRequest.

Here is my implemented code:

1. Configure the resource handler:

@Override
public void addResourceHandlers(final ResourceHandlerRegistry registry) {
    registry.addResourceHandler("/css/**")
    .addResourceLocations("classpath:/css/")
            .setCachePeriod(31556926);
}
  1. Retrieve the base URL from HttpServletRequest, either by injecting it into the method, autowiring it in the service class, or accessing it via RequestContextHolder. In my Service class, the method getCurrentBaseUrl() accomplishes this task:

    private static String getCurrentBaseUrl() {
    ServletRequestAttributes sra = (ServletRequestAttributes)RequestContextHolder.getRequestAttributes();
    HttpServletRequest req = sra.getRequest();
    return req.getScheme() + "://" + req.getServerName() + ":" + req.getServerPort() + req.getContextPath();
    } 
    
  2. This section demonstrates how the template engine is utilized in my class:

        Context context = new Context();
        context.setVariable("variales", variables);
        context.setVariable("baseUrl", getCurrentBaseUrl());
        String content = springTemplateEngine.process("myTemplate",context);
    
  3. In my template file, absolute CSS URLs are employed as follows:

    <link type="stylesheet" th:src="@{|${baseUrl}/css/style.css|}" />
    

Answer №2

To fix the issue, I made adjustments to the path structure within the href attribute. My setup mirrored yours, with HTML files residing in the templates folder and CSS files in the static folder.

<head>
    <title>Example Using Spring Boot and Thymeleaf</title>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
    <link rel="stylesheet" type="text/css" href="/css/style.css"/> 
</head>

Implementing these changes should allow you to successfully style your HTML page with CSS.

Answer №3

If you're struggling with this issue, make sure to specify the request mapping for your folders correctly when using the Spring Security dependency. You should organize your CSS file under the static/css folder in your project.

Once you have done that, include a link to the CSS file in your HTML code like this:

<link rel="stylesheet" th:href="@{/css/index.css}">

I hope this information proves helpful to someone out there!

Answer №4

The syntax appears to be correct, so the issue is likely not related to syntax errors.

Additionally, attempting to utilize the @{...} syntax without an IWebContext interface will result in the exception you are currently experiencing.

Answer №5

I have discovered a clever shortcut for handling this task efficiently. The solution is straightforward and effective. Instead of using the traditional method, I simply insert a CSS style tag directly into the body of a basic HTML document. This can be done by placing the following code within the HEAD section of my desired file:

<th:block th:insert="std-reports/std-reports-css-fragment.html :: style"></th:block>

Answer №6

Dealing with a similar issue, I ran into a problem where my template page was not picking up the CSS styles.

The root cause of my problem turned out to be that the CSS file was in SASS format:

.table
   margin: 0 0 40px 0

After converting it to traditional CSS format like this:

 .table {
  margin: 0 0 40px 0;
  }

Voila! It worked like a charm.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Convert traditional class-based styles to inline styles

Is there a tool available that can efficiently convert class-based styles to inline styles? I am designing an email and find it much easier and quicker to work with classes, but the final output requires inline styles. It seems like there should be softwar ...

Align the first div in the center horizontally alongside the other inline-block div

There are two div elements styled with display: inline-block; to place them on the same line. I am looking to horizontally center the first div and position the second div just to the right of it. Similar to the layout below: page text page text page te ...

I am encountering difficulties displaying the image and CSS files from another folder in my HTML with Node.js

I am facing difficulty in establishing a connection between my front-end and back-end using node.js. As a result, the website only displays the HTML code without linking to the CSS or image files. Here is the folder structure: root -src •pi ...

What are the steps to transforming shorthand CSS into longhand?

Is there a tool available that can automatically convert shorthand CSS to longhand? I am in need of this functionality because I would like to utilize SmartSprites, which is not compatible with shorthand formatting. Additionally, if there is a tool that c ...

Customizing the Collapse Button CSS in Datatables

I am looking to customize the CSS of the collapse button on this particular example https://datatables.net/extensions/searchpanes/examples/customisation/buttonText.html I have already conducted numerous searches and attempted various solutions. ...

Looking for assistance with resizing SVG images

I am facing some challenges with the HTML/CSS code to make all SVG's scale uniformly in terms of height/width. I have set up a simple structure but I'm unsure of what steps to take next. When I view the images in the browser, they are all scaled ...

What is the best way to create a flawless circular image with a card in Bootstrap 5?

For my project, I incorporated Bootstrap version 5 cards. I attempted to create a perfect circle image by utilizing the Bootstrap class "rounded-circle", however, the resulting image ended up appearing oval in shape. Below is the code snippet: <img src ...

What are some alternative ways to create a text field with the same style as Material UI's without relying on the Material UI

With the power of HTML, CSS, and Reactjs I am aiming to create a functionality where the placeholder animates up to the border upon clicking on the text field An example can be seen with Material UI text field: https://material-ui.com/components/text-fie ...

What is the process for customizing the onmouseover property in HTML?

I am currently working on customizing tabs. I want to underline the title of the active tab, but for some reason I am having trouble achieving this with CSS. It seems like I might need a CSS syntax that I am not familiar with. As a solution, I am consider ...

Tips for preventing background scrolling of a Fixed element in React

Currently, I am working on a project using NextJS with Tailwind CSS. I am in the process of creating a drawer, popup, and modal with the CSS property position: fixed. However, I have encountered an issue where when I scroll on the fixed elements, the bac ...

Issues arising with the functionality of CSS media queries when used in conjunction with the

I created a webpage that is functioning well and responsive on its own. However, when I integrate the same files with the Spring framework, the responsiveness of the webpage seems to be lost. To ensure the responsiveness of the Spring webpage, I tested it ...

Is the lack of style in PHP echo using Ajax causing issues?

Encountered a Blocking Issue. Started by creating a PHP page incorporating HTML, CSS, JS, and PHP elements. The goal was to allow users to view events based on the selected date within this file. To achieve this, the selected date's value was int ...

What is causing the animate callback to not properly wait for the completion of the animations?

Both animations are triggered simultaneously (sometimes even multiple times).... <div id="home-bt" class="button"></div> <div id="about-bt" class="button"></div> <div id="beauty-bt" class="button"></div> <div id="pam ...

I am attempting to create a webpage with a primary center image and two additional images on either side using PHP or HTML

I have a coding dilemma - I want to display three images in a single row, one in the center, one on the left, and one on the right. However, my current PHP code is causing the left and right images to appear below the center image. How can I adjust my co ...

Relative positioning of DIV elements

Often, I come across code that looks like this: #container { background:#000000 none repeat scroll 0 0; display:block; overflow:hidden; position:relative; width:100%; } I have always believed that the 'position: relative' CS ...

Condition-based migrations with Liquibase

Looking to streamline migration processes for the following technology stack: Java, Maven, Spring-Boot, Postgres, Liquibase. Wondering if it's feasible to delay execution of certain liquibase change logs until a specific version of a maven module? F ...

Create a CSS image slider with a border around the images and two navigation buttons using z-index

I am looking to design an image slider with a border around the images and transitioning effects similar to the provided screenshot. Here is my HTML code: <div id="slideshow"><span class="control" id="leftControl" style="display: none;" ...

Difficulty arising while trying to access the following element after the designated target using JQuery

JSFiddle I'm encountering a strange issue in the fiddle linked above. When typing a character into an input followed by pressing the down key, the console logs two values: one correct value of 3, and one incorrect value of 0. The challenge is to sel ...

Tips for showcasing div content on a separate line rather than inline within a collapsible <a> tag

I am currently working on integrating a sidebar using bootstrap 5. When I click on the user initials, I want something like this to happen (collapse): https://i.sstatic.net/ejbhD.png However, the result I'm getting is different: https://i.sstatic. ...

Ways to insert a hyphen "-" in an HTML form

Currently, I am in the process of designing a form for entering my bank account number. I would like to add a checkbox that will automatically populate the field for easier viewing. <input class="form-control" type="text" placehol ...