Customize CSS based on user's device in Google Script Web App

Seeking Clarity:

I have a straightforward project involving a Google Script / Web App, but I am struggling to find a way to load a specific CSS file based on the user's device.

In other words, rather than focusing on responsive design, I need to load different CSS files depending on the user's device for certain requirements.

My setup consists of:

Index.html | css1.html | css2.html

Here is the code snippet from my Index.html file:

<!DOCTYPE html>
    <html>
      <head>
        <base target="_top">
        <? if (/Mobi/.test(navigator.userAgent)) {?>
            <?!= HtmlService.createHtmlOutputFromFile('css1').getContent(); ?>
          <?} else {?>
            <?!= HtmlService.createHtmlOutputFromFile('css2').getContent(); ?>
          <?}?>
      </head>
      <body>
         <p> THIS is a TEST </p>
      </body>
    </html>

However, when I deploy and test this code, I encounter an error: ReferenceError: navigator is not defined (line 5)

The code referenced above that works can be found here.

I have tried alternative methods like @media load, but none seem to work. While I can load different pages based on the user's device, I would prefer it to be a CSS-specific solution.

---> Edit: code.gs

function doGet(e) 
{
    var html      = HtmlService.createTemplateFromFile('Index');  
    var pageData  = html.evaluate()
                    .setTitle('Web App 1')                        
                    .setFaviconUrl('https://www.gstatic.com/images/icons/material/product/2x/apps_script_64dp.png')
                    .setSandboxMode(HtmlService.SandboxMode.IFRAME)                            
                    .addMetaTag('viewport', 'width=device-width, initial-scale=1')            
                    .setXFrameOptionsMode(HtmlService.XFrameOptionsMode.ALLOWALL)               
    return pageData;
}
function include(filename)
{
  return HtmlService.createHtmlOutputFromFile(filename)
        .getContent();
};

---> css1.html

<style>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.1/css/bootstrap.min.css" 
integrity="sha384-WskhaSGFgHYWDcbwN70/dfYBj47jz9qbsMId/iRN3ewGhXQFZCSftd1LZCfmhktB"
crossorigin="anonymous">
<style>

p {
  color: blue;
}

</style>

---> css2.html

<style>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.1/css/bootstrap.min.css" 
integrity="sha384-WskhaSGFgHYWDcbwN70/dfYBj47jz9qbsMId/iRN3ewGhXQFZCSftd1LZCfmhktB"
crossorigin="anonymous">
<style>

p {
  color: red;
}

</style>

In attempting @Media approach in the <head>, I used the following which did not yield results:

<link rel="stylesheet" media='screen and (min-width: 140px) and (max-width: 380px)' href="css1"/>
<link rel="stylesheet" media='screen and (min-width: 381px) and (max-width: 700px)' href="css2"/>

Answer №1

Upon reviewing your provided script, it appears that navigator.userAgent belongs to Javascript and not Google Apps Script. To select CSS based on the value of navigator.userAgent, one possible approach involves the following steps.

  1. Retrieve the value of navigator.userAgent when the HTML page is loaded.
  2. Send this value to Google Apps Script.
  3. At the Google Apps Script side, return the selected CSS based on the received value.

If you wish to implement this flow in a simple sample script, consider the following examples:

Option 1:

This scenario utilizes google.script.run.

HTML & JavaScript:

<!DOCTYPE html>
<html>

<head>
  <base target="_top">

  <script>
  google.script.run.withSuccessHandler(e => {
    console.log(e); // Check the returned CSS in the console
    document.querySelector("head").insertAdjacentHTML('beforeend', e); // or 'afterBegin'
  }).getStyle(/Mobi/.test(navigator.userAgent))
  </script>
</head>

<body>
  sample
</body>

</html>

Google Apps Script:

const getStyle = e => HtmlService.createHtmlOutputFromFile(e ? 'css1' : 'css2').getContent();

function doGet() {
  var html = HtmlService.createHtmlOutputFromFile('Index');
  var pageData = html
    .setTitle('Web App 1')
    .setFaviconUrl('https://www.gstatic.com/images/icons/material/product/2x/apps_script_64dp.png')
    .setSandboxMode(HtmlService.SandboxMode.IFRAME)
    .addMetaTag('viewport', 'width=device-width, initial-scale=1')
    .setXFrameOptionsMode(HtmlService.XFrameOptionsMode.ALLOWALL)
  return pageData;
}

Option 2:

In this case, an HTML template is utilized where both CSS files are included upon opening the HTML. The appropriate CSS file is then chosen based on navigator.userAgent.

HTML & JavaScript:

<!DOCTYPE html>
<html>

<head>
  <base target="_top">

  <script>
    const css1 = `<?!= HtmlService.createHtmlOutputFromFile('css1').getContent(); ?>`;
    const css2 = `<?!= HtmlService.createHtmlOutputFromFile('css2').getContent(); ?>`;
    document.querySelector("head").insertAdjacentHTML('beforeend', /Mobi/.test(navigator.userAgent) ? css1 : css2); // or 'afterBegin'
  </script>
</head>

<body>
  sample
</body>

</html>

Google Apps Script:

function doGet() {
  var html = HtmlService.createTemplateFromFile('Index');
  var pageData = html.evaluate()
    .setTitle('Web App 1')
    .setFaviconUrl('https://www.gstatic.com/images/icons/material/product/2x/apps_script_64dp.png')
    .setSandboxMode(HtmlService.SandboxMode.IFRAME)
    .addMetaTag('viewport', 'width=device-width, initial-scale=1')
    .setXFrameOptionsMode(HtmlService.XFrameOptionsMode.ALLOWALL)
  return pageData;
}

Note:

  • This script is simplistic. Please customize it accordingly to fit your specific requirements.

  • If you make changes to the Google Apps Script for Web Apps, ensure to redeploy it as a new version so the modifications take effect. Exercise caution when doing this.

  • For further details, refer to my report titled "Redeploying Web Apps without Changing URL of Web Apps for new IDE (Author: me)".

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

What is the process for defining a global variable within a module in Typescript?

I've already included a global value in my global JavaScript context: const fs = require('fs') For a specific reason, I need to include it in the global scope. Now, I want to create a .d.ts file to declare the global variable with a stron ...

Before you start interactivity in three.js, you will be presented with a classic

Recently, I incorporated a 3D WebGL viewer into my website, but I encountered a minor problem. Although everything functions properly and I am able to manipulate the object, there is a brief moment of a black screen upon loading the page before moving the ...

Leveraging JSON data to dynamically create HTML elements with multiple class names and unique IDs, all achieved without relying on

Recently, I've been working on creating a virtual Rubik's cube using only JS and CSS on CodePen. Despite my limited experience of coding for less than 3 months, with just under a month focusing on JS, I have managed to develop two versions so far ...

Waiting for the completion of the ScrollIntoView operation using Selenium

Whenever I try to scroll to a specific element and take a screenshot of the page, the driver captures the screenshot before the page has fully scrolled to the element. To address this, I initially included a time sleep in my code: driver.execute_script(&qu ...

Is it possible for a dropdown to span 100% of the width

http://jsfiddle.net/gL1xynzr/ Is there a way to style a dropdown menu with the following properties: width: 100%; max-width: 440px; I am planning to include 4 of these dropdowns in one CSS table row to ensure they fit horizontally on mobile phone portra ...

Incorporating CSS into an HTML page created by a Python CGI script

Last week, I was handed a Python-based monitoring and notification tool to work on. My task is to develop a proof of concept dashboard using the data collected by this tool over the years. The catch is that I'm fairly new to Python and have never dabb ...

Error encountered on page load due to undefined variable thrown by the Express-validator validation process

In the process of constructing a contact form and incorporating express-validator for validation, I am currently focused on error handling. Below is a snippet of the code from my app.js file that pertains to this matter: // CREATE (POST) ROUTE - add new p ...

Exploring LZMA compression in conjunction with next.js

Is anyone familiar with using the lzma algorithm to compress video, photo, text, etc. in the Next.js framework? I have searched everywhere but couldn't find a solution. I haven't found a proper demonstration or answer anywhere. I would greatly a ...

Analyzing JSON parsing efficiency

I am currently working on a client application using jquery and html5 For my project, I have a data file that is 70 MB in size The file named data.json contains the following: var myData = [ { "id":"000000001", "title":"title1", "c ...

What's the best way to include various type dependencies in a TypeScript project?

Is there a more efficient way to add types for all dependencies in my project without having to do it manually for each one? Perhaps there is a tool or binary I can use to install all types at once based on the dependencies listed in package.json file. I ...

Horizontally position the main word from the D3-WordCloud in the center

I am working on a WordCloud project and have utilized code from Jason Davies D3-JavaScript-WordCloud Example, which can be found at this link. The majority of the code I have used is from a helpful tutorial in German by Lars Ebert, available at this URL. ...

Create a DIV element that completely fills the vertical space available

My webpage is currently looking quite empty, with only one DIV element present: <div style="height: 20%; min-height: 10px; max-height: 100px; width: 100%; background-color: blue;"></div> I' ...

Streamline the testing process to ensure compatibility with jQuery version 2.x

I currently have a substantial JavaScript code base that is all built on jQuery 1.8. I am planning to upgrade to jQuery 2.1 in the near future and I am fully aware that many parts of my code will likely break during this process. Is there any efficient me ...

The browser is throwing errors because TypeScript is attempting to convert imports to requires during compilation

A dilemma I encountered: <script src="./Snake.js" type="text/javascript"></script> was added to my HTML file. I have a file named Snake.ts which I am compiling to JS using the below configuration: {target: "es6", module: "commonjs"} Howeve ...

How about creating a responsive layout using only CSS3 for dynamic width adjustments?

I'm struggling to solve a design challenge involving three columns: a navbar (dark gray), main content (dark red), and sidebar (dark green). The navbar should be expandable and collapsible, while the sidebar should slide in and out. My goal is to make ...

Can we be confident in the security and effectiveness of utilizing ajax for login implementation?

Hello, I've written the code below to verify if a user is eligible to log in to a database. I've utilized SSL to secure the connection, but I'm unsure if this is still an effective method. Could anyone provide some advice? Thank you for your ...

Failure to trigger success or error callbacks in Angular's $http.get request

Trying to access the nutritionix v1_1 API through a get request has been a bit tricky. Despite the function being called successfully and passing the correct data, the $http.get request seems to be causing some trouble. It simply skips over the remaining c ...

Is it considered a best practice to utilize JavaScript for positioning elements on a

I recently started learning JavaScript and jQuery, and I've been using them to position elements on my website based on screen and window size. It's been really helpful, but I'm starting to wonder if it's a good practice since it makes ...

Using multiple <img> tags with identical src attributes

Imagine having a large number of <img> tags all with the same src value, like this: <img src="https://something.com/images/myimg.png" alt="" /> <img src="https://something.com/images/myimg.png" alt="" /> <img src="https://something.co ...

Which library does stackoverflow utilize to showcase errors (utilizing Bootstrap popover for error help-block)?

Currently, I am using bootstrap's has-error and help-block classes to display validation error messages in my form. However, I find the error message display in Stackoverflow's Ask Questions Form to be very appealing. Are they using a specific js ...