Adam Gardner
Adam Gardner

Reputation: 65

Create CSS Selector Using JavaScript

I'm trying to create CSS Selectors using JavaScript for certain browsers and on mobile. This is the method that already works:

// CHECK BROWSER AND SET AS CSS METHOD
    function getBrowserName() {
        var name = "Unknown";
        if(navigator.userAgent.indexOf("MSIE")!=-1){
            name = "msie";
        } if(navigator.userAgent.indexOf("Trident")!=-1){
            name = "msie";
        } if(navigator.userAgent.indexOf("Edge")!=-1){
            name = "msie";
        } else if(navigator.userAgent.indexOf("Firefox")!=-1){
            name = "firefox";
        } else if(navigator.userAgent.indexOf(" OPR/")>=0){
            name = "opera";
        } else if(navigator.userAgent.indexOf("Chrome") != -1){
            name = "chrome";
        } else if(navigator.userAgent.indexOf("Safari")!=-1){
            name = "safari";
        }
        return name;   
    }

    if (getBrowserName() != "Unknown"){
        document.getElementsByTagName('html')[0].className += "is-" + getBrowserName(name);
    }

This works great by calling .is-(browser-name element-selector { css }. However, I can't get this to work for mobile. Here's my code...

var mobile = (/iphone|ipod|android|blackberry|mini|windows\sce|palm/i.test(navigator.userAgent.toLowerCase()));  
if (mobile) { 
    document.getElementsByTagName('html')[0].className += "is-mobile";
}

I've been using everything outside of the if (mobile) section with jQuery, which already works, but I would like to make this process a bit quicker using regular CSS and JavaScript. I'd include a working code snippet, but it obviously won't work since my current code depends on the user using certain browsers...I've included a sample in the hopes it might be easier to read.

Does anyone have any idea why this code works for the different browsers section, but not the mobile? Thanks for the help!

// WORKS
function getBrowserName() {
  var name = "Unknown";
  if (navigator.userAgent.indexOf("MSIE") != -1) {
    name = "msie";
  }
  if (navigator.userAgent.indexOf("Trident") != -1) {
    name = "msie";
  }
  if (navigator.userAgent.indexOf("Edge") != -1) {
    name = "msie";
  } else if (navigator.userAgent.indexOf("Firefox") != -1) {
    name = "firefox";
  } else if (navigator.userAgent.indexOf(" OPR/") >= 0) {
    name = "opera";
  } else if (navigator.userAgent.indexOf("Chrome") != -1) {
    name = "chrome";
  } else if (navigator.userAgent.indexOf("Safari") != -1) {
    name = "safari";
  }
  return name;
}

if (getBrowserName() != "Unknown") {
  document.getElementsByTagName('html')[0].className += "is-" + getBrowserName(name);
}

// DOESN'T WORK
var mobile = (/iphone|ipod|android|blackberry|mini|windows\sce|palm/i.test(navigator.userAgent.toLowerCase()));

if (mobile) {
  document.getElementsByTagName('html')[0].className += "is-mobile";
}

// WORKS
if (mobile) {
  $(".about-text").css("width", "90%");
  $("body").css("font-size", "50px");
  $("section").css("padding-top", "160px");
}
/* works */
.is-msie hr {
  margin: 50px 0 10px 0;
}


/* doesn't work */
.is-mobile hr {
  margin: 50px 0 10px 0;
}
<!--REPEATING TABLE WITH HR FOR SEPARATORS -->
<div class="col span-1-of-2 table right-col">
  <hr>
  <div>
    <div class="col span-1-of-8 date">
      <p><span>12</span> Nov.</p>
    </div>
    <div class="col span-1-of-8 venue">
      <p>The Venue</p>
    </div>
    <div class="col span-1-of-8 city">
      <p>San Francisco, CA</p>
    </div>
    <div class="col span-1-of-8 rsvp desktop">
      <div><a class="btn-sm btn-full" href="#">RSVP</a></div>
    </div>
    <div class="col span-1-of-8 tickets desktop">
      <div><a class="btn-sm btn-ghost" href="#">Tickets</a></div>
    </div>
    <div class="col span-2-of-8 info">
      <div><a class="btn-sm btn-full" href="#">Info</a></div>
    </div>
  </div>
  <hr>
  <div>
    <div class="col span-1-of-8 date">
      <p><span>12</span> Nov.</p>
    </div>
    <div class="col span-1-of-8 venue">
      <p>The Venue</p>
    </div>
    <div class="col span-1-of-8 city">
      <p>San Francisco, CA</p>
    </div>
    <div class="col span-1-of-8 rsvp desktop">
      <div><a class="btn-sm btn-full" href="#">RSVP</a></div>
    </div>
    <div class="col span-1-of-8 tickets desktop">
      <div><a class="btn-sm btn-ghost" href="#">Tickets</a></div>
    </div>
    <div class="col span-2-of-8 info">
      <div><a class="btn-sm btn-full" href="#">Info</a></div>
    </div>
  </div>
  <hr>
  <div>
    <div class="col span-1-of-8 date">
      <p><span>12</span> Nov.</p>
    </div>
    <div class="col span-1-of-8 venue">
      <p>The Venue</p>
    </div>
    <div class="col span-1-of-8 city">
      <p>San Francisco, CA</p>
    </div>
    <div class="col span-1-of-8 rsvp desktop">
      <div><a class="btn-sm btn-full" href="#">RSVP</a></div>
    </div>
    <div class="col span-1-of-8 tickets desktop">
      <div><a class="btn-sm btn-ghost" href="#">Tickets</a></div>
    </div>
    <div class="col span-2-of-8 info">
      <div><a class="btn-sm btn-full" href="#">Info</a></div>
    </div>
  </div>
  <hr>
  <div>
    <div class="col span-1-of-8 date">
      <p><span>12</span> Nov.</p>
    </div>
    <div class="col span-1-of-8 venue">
      <p>The Venue</p>
    </div>
    <div class="col span-1-of-8 city">
      <p>San Francisco, CA</p>
    </div>
    <div class="col span-1-of-8 rsvp desktop">
      <div><a class="btn-sm btn-full" href="#">RSVP</a></div>
    </div>
    <div class="col span-1-of-8 tickets desktop">
      <div><a class="btn-sm btn-ghost" href="#">Tickets</a></div>
    </div>
    <div class="col span-2-of-8 info">
      <div><a class="btn-sm btn-full" href="#">Info</a></div>
    </div>
  </div>
  <hr>
</div>

Upvotes: 2

Views: 684

Answers (2)

Adam Gardner
Adam Gardner

Reputation: 65

The space was part of the issue. Thank you all for helping me with that. The real problem though, for some reason, was I had to replace the "html" in that line with "body, so the line now looks like this...

document.getElementsByTagName('body')[0].className += " is-mobile";

Thank you all for your responses! I will post a rewritten form of the code tomorrow.

EDIT: For some reason, after I rearranged a few things in my document, my old code actually worked...even though it wouldn't work the way I wrote above before rearranging it. I'm posting the new format with multiple files, but here's what my code now looks like:

File that assigns CSS Classnames. Called in header

// ASSIGN CLASSNAME TO MOBILE DEVICES
var mobile = (/iphone|ipod|android|blackberry|mini|windows\sce|palm/i.test(navigator.userAgent.toLowerCase()));  

if (mobile) { 
    document.getElementsByTagName('html')[0].className += " is-mobile";
}

// $(".about-text").css("width", "90%");


// ASSIGN CLASSNAME TO APPLE DEVICES
var appleDevice = (/iphone|ipod/i.test(navigator.userAgent.toLowerCase()));

if (appleDevice) {
    document.getElementsByTagName('html')[0].className += " is-apple";
}

// CHECK BROWSER AND ASSIGN APPROPRIATE CLASSNAME
function getBrowserName() {
    var name = "Unknown";
    if(navigator.userAgent.indexOf("MSIE")!=-1){
        name = "msie";
    } if(navigator.userAgent.indexOf("Trident")!=-1){
        name = "msie";
    } if(navigator.userAgent.indexOf("Edge")!=-1){
        name = "msie";
    } else if(navigator.userAgent.indexOf("Firefox")!=-1){
        name = "firefox";
    } else if(navigator.userAgent.indexOf(" OPR/")>=0){
        name = "opera";
    } else if(navigator.userAgent.indexOf("Chrome") != -1){
        name = "chrome";
    } else if(navigator.userAgent.indexOf("Safari")!=-1){
        name = "safari";
    }
    return name;
}

if (getBrowserName() != "Unknown"){
    document.getElementsByTagName('html')[0].className += " is-" + getBrowserName(name);
}

File that removes items from DOM based on mobile or browser. Called before all other script tags in footer for faster loading.

var music = document.getElementById("music");
var musicLink = document.getElementById("music-link");
var photos = document.getElementById("photos");
var photosLink = document.getElementById("photos-link");

if (mobile) {
    music.parentNode.removeChild(music);
    musicLink.parentNode.removeChild(musicLink);
    photos.parentNode.removeChild(photos);
    photosLink.parentNode.removeChild(photosLink);
}

if (getBrowserName() == "msie") {
    photos.parentNode.removeChild(photos);
    photosLink.parentNode.removeChild(photosLink);
}

The rest is in a separate JS file with jQuery and mostly irrelevant to this post. Thanks again for everyone's help!

Upvotes: 0

cchamberlain
cchamberlain

Reputation: 17956

At a minimum you need a space prior to the "is-mobile". className is a space separated list so your current implementation breaks both of your checks on a mobile device.

Something like this splits the existing class names into an array, concatenates the one you want, then joins them all with space separation:

(document.getElementsByTagName('html')[0].className || "").split(" ").concat(["is-mobile"]).join(" ");

I'd recommend the use of an ES6 Set here (if your browsers support it) to avoid worrying about duplicate class names:

let htmlElement = document.querySelector('html')

// Use a Set to avoid duplicates.
let classNames = new Set((htmlElement.className || '').split(' '))
classNames.add('is-safari')
classNames.add('is-mobile')

// Convert the set of class names to an array and join them.
htmlElement.className = Array.from(classNames).join(' ')

console.log(htmlElement.className)

Upvotes: 2

Related Questions