Category Archives: CSS

Angular and Scrolling Content

15 Oct 2015

I’m currently enrolled at Thinkful.com in the Angular course. I’m well over half-way through and have been applying Angular to my work projects with great success. One thing that I needed to do was to have scrolling views in my hybrid apps while having other areas of the app remain static. My future goals involve using Ionic – which handles scrolling easily enough, and I suspect, in the exact same way I’ve done it here – but I’m a logical step-by-step kind of guy so for now I’m content with learning Angular and rolling my own UI. That being the case I thought to search for the “Angular” way of getting views to scroll and tried a few of the custom directives available on the Internet.

The easiest to set up was ng-scrollable which technically worked but lacked the finesse of the vaunted iScroll. I also tried angular-iscroll but without much success. I reverted to the usually reliable iScroll but Angular didn’t want to play nicely with it. I then reverted to ng-scrollable thinking I could revisit it and proceeded with my other layout duties only to find that ng-scrollable injected too much crap into the DOM which broke a previously working flex-box-based layout. Attempts to rectify the layout proved to be a waste of time. So, I removed ng-scrollable and instead pursued a native / pure css solution.

The Technique

So lets get back to what I wanted – native-like smooth scrolling with inertia. The answer can be found via CSS by creating a class with the following properties (your wrapping container must have a set width / height, and a setting of “overflow:hidden” on the wrapper will kill scrolling):

.scrollable {
    overflow-x: hidden; // Control how to clip the container's content.
    overflow-y: scroll;
    -ms-overflow-style: -ms-autohiding-scrollbar; // configure overflow scrolling behavior for IE 10
    -webkit-overflow-scrolling: touch; // The magic happens here
}

Each of the above styles are configured as follows:

  • -webkit-overflow-scrolling
    • auto – Non-inertia scrolling. Scrolling stops as soon as your finger no longer touches the screen.
    • touch – Use inertia-based scrolling, the faster you flick the scrollable content the faster it scrolls but continues to a deaccelration scroll whne your finger stops touching the screen. I find this to be the desired behavior as its closest to native on Mobile.
  • overflow-x, overflow-y – These properties specify how to treat overflowing content via one of the following values:

    • visible – Indicates the content is not clipped, it may be rendered outside the content box.
    • hidden – Indicates the content is clipped and no scrollbars are provided.
    • scroll – Indicates the content is clipped and desktop browsers use scrollbars whether or not any content is clipped. For hybrid application development the scrolling behavior mimics native scrolling where scroll bars don’t appear unless you interact with the scrollable content. On Android at least the scrollbar overlaps content so you should add padding to account for it. On desktop the scrollbars use up additional space within the scrolling wrapper.
    • auto – Depends on the user agent – meaning that you should expect the native behavor for the overflowing content.

I’m not too concerned with IE in my hybrid app development but here are the configuration options none-the-less:

  • -ms-overflow-style – Sets the scrolling behavior for overflowing elements in IE (copied from MS).

    • auto – Indicates the element inherits its -ms-overflow-style from its parent element
    • none – Indicates the element does not display scrollbars or panning indicators, even when its content overflows. Unlike overflow: hidden, elements with -ms-overflow-style: none can still be scrolled via touch panning, keyboard, or mouse wheel.
    • scrollbar – Indicates the element displays a classic scrollbar-type control when its content overflows.
    • -ms-autohiding-scrollbar – Indicates the element displays auto-hiding scrollbars during mouse interactions and panning indicators during touch and keyboard interactions.

Notes

If using this on Android / PhoneGap be sure to install the Crosswalk plugin so that you don’t have to worry about compatibility with older webkits.

Also, it is worth noting that sometimes it wont work unless you apply the webkit-specific styling directly to the element like so:

<div id="comeContent" style="-webkit-ovrflow-scrolling: touch;">...

Also worth noting is that if the content of the scrolling element changes that you may need to force the content heights to be recalculate on iOS by inserting a psuedo-element using a simple calc() function to determine its new height:

#comeContent:before {
  content:'';
  width: 1px;
  float: left; // remove from the document flow
  height: calc(100% + 1px); // force the recalculation of the container's height
  margin-left: -1px; // remove from view
}

Other methods of forcing a screen redraw may work as well.

Eliminating Touch Event Lag via CSS

12 Mar 2014

It’s common knowledge that ontouchstart on mobile doesn’t fire immediately because a 300ms pause is implemented in WebKit to determine if the touchstart is the beginning of a double-tap. For that reason, web app developers use the ontouchend event instead because it doesn’t have any built-in delays.

Some people will try to code around the issue by synthesizing a touchend event when touchstart is detected thereby skirting the inherent delay. FastClick is an example of this sort of work-around.

If you find that you need to make a “click-based” application feel more responsive you could try something like the above – or you could just try some CSS. Its possible to eliminate the standard 300ms delay entirely without any JavaScript:

.yourButtonClass, a {
    -ms-touch-action: none; // Deprecated as of IE 11, Microsoft recommends the the standard below
     touch-action: none; // webkit
}

Related to this topic is this dated article at Quirks Mode which I found to of interest (keep in mind its from 2010): The touch action.

Setting CSS Background Colors via Javascript – RGB triplet vs Hex

10 Oct 2012

We’ve all had to do it – change the color of text or visible html elements like Div backgrounds or borders, etc. One thing I’ve noticed is that when I request the background color of a Div I get the RGB triplet, not a hexadecimal value. Observe this example:

(Please use a modern browser, I’ve made no effort to make the examples work in old browsers)

<html><head><title></title>
<script language="javascript">
  function getColor(){
    document.getElementById('result').innerHTML = document.getElementById('dd').style.backgroundColor;
  }
</script>
</head>
<body>
<p><a href="javascript:getColor()">Click here to get the color of the box</a></p>
<p>The box color is: <span id="result"></span></p>
<div style="height:100px;width:100px;background-color:#185f8e;border:1px solid #ccc;" id="dd"></div>
</body>
</html>

 

Notice that the color obtained is not the hexadecimal value that you saw in the sample source provided above but the RGB equivalent even though its Hexadecimal to begin with.

Next, if I were to attempt to change the color by setting the css background-color value to an RGB value nothing will happen. See this example:

<html><head><title></title>
<script language="javascript">
function setColor(){
  document.getElementById('result').style.backgroundColor = 'rgb(122, 122, 122)';
}
</script>
</head>
<body>
<p><a href="javascript:setColor()">Click here to change the box color with an RGB value: rgb(122, 122, 122);</a></p>
<p>The box color is: <span id="result"></span></p>
<div style="height:100px;width:100px;background-color:#185f8e;border:1px solid #ccc;" id="dd"></div>
</body>
</html>

 

As you can see… nothing happens…. so in order to change the background color you must use a hexidecimal value.

If we get a hex value from an element it will be RGB so in order to make it useful elsewhere in our code we would need to convert the RGB back to hexadecimal. Below is a function I wrote that will do that for us.

...
function convertToHex(str){
  var raw = str.match(/(\d+)/g);
  var hexr = parseInt(raw[0]).toString(16);
  var hexg = parseInt(raw[1]).toString(16);
  var hexb = parseInt(raw[2]).toString(16);
      hexr = hexr.value == 1 ? '0' + hexr: hexr;
      hexg = hexg.length == 1 ? '0' + hexg: hexg;
      hexb = hexb.length == 1 ? '0' + hexb: hexb;
  var hex = '#' + hexr + hexg + hexb;
  return hex;
}
...

This function takes an RGB of the following format: rgb(x, x, x) where “x” is any number within the RGB number range. The short description of what is happening would be to say that hexadecimal is base 16, thus the toString(16) which gives us the hex equivalent of each individual RGB value.

The long description would to say that the basic usage of toString() is to convert a number to a string, but we can also pass an argument to the toString() method to tell it what base to convert the number to. A few different bases are available. If we wanted to convert a number to binary we would use toString(2) (pronounced to string base 2), to octal, we would use toString(8) and finally to convert to hexadecimal we use toString(16). Using a base of 10 as in toString(10) is the same as using nothing at all – base 10 is decimal which is what numbers are to begin with.

An interesting thing to note is that hexadecimal is a numbering system from 0 to 9 and then continuing from A to F which totals 16 characters. 15 in hex is “f” which is just one character in length. 16 is two characters – ’10’. So any RGB value lower than 16 in hexadecimal will be a single character in length. Such values need to be left-padded by a zero since a hexadecimal color is always a total of 6 characters (2 characters per R, G, and B). To use our example, 15 = f in hex, we need to left zero pad it to be “0f”. If your RGB value is rgb(15, 15, 15) the proper hexadecimal value would be “0f0f0f” and not “fff” (which is a completely different color, see below). You can see the zero-padding happening in the ternary operators on lines 7, 8, and 9.

The caveat to all of this are the “shortcode” hex values that you see from time to time. Such as “fff” for white which in its full form is “ffffff”, or “ccc” for a light grey which is really “cccccc”. How about this shortened hex: “7de” – that would be “77ddee”. See the pattern? If a browser sees a 3 character hex value then each individual character must represent R, G, and B. In the absence of any other data the rest of the hex values are implied by the existing data, so “7” = “77, “d” = “dd” and “e” = “ee”. It is then necessary to give a browser a full hexadecimal value where necessary to get the actual colors, not implied colors. Left zero-padding where needed achieves this.

So here now is my last example using a color palette toolbar to change the color of a Div element, where I take the background color of the clicked Div element, which is revealed as RGB, convert it back to hexadecimal and apply it to the color box:

<html><head><title></title>
<script language="javascript">
  function convertToHex(str){
    var raw = str.match(/(\d+)/g);
    var hexr = parseInt(raw[0]).toString(16);
    var hexg = parseInt(raw[1]).toString(16);
    var hexb = parseInt(raw[2]).toString(16);
        hexr = hexr.length == 1 ? '0' + hexr: hexr;
        hexg = hexg.length == 1 ? '0' + hexg: hexg;
        hexb = hexb.length == 1 ? '0' + hexb: hexb;
    var hex = '#' + hexr + hexg + hexb;
    return hex;
  }

  window.addEventListener('load',function(){
    document.getElementById('colorWrapper').addEventListener('click',function(e){
      if (e.target.attributes['class'].nodeValue == 'colorSwatch'){
        document.getElementById('box').style.backgroundColor = convertToHex(e.target.style.backgroundColor);
      }
    },false);
  },false);
</script>
<style type="text/css">
  #colorWrapper{
    padding:0px 8px 8px 8px;
    border:1px solid #000;
    width:228px;
    margin: 0px 0px 20px 0px;
  }
  .colorSwatch{
    height:50px;
    width:50px;
    display:inline-block;
  }
</style>
</head>
<body>

<div id="colorWrapper">
  <p>Select a color to change the box's background color.</p>
  <div class="colorSwatch" style="background-color:#5d8eae"></div>
  <div class="colorSwatch" style="background-color:#adae5d"></div>
  <div class="colorSwatch" style="background-color:#78ae5d"></div>
  <div class="colorSwatch" style="background-color:#a05dae"></div>
</div>
<div style="height:100px;width:100px;background-color:#185f8e;border:1px solid #ccc;" id="box"></div>
</body>
</html>

 

An interesting thing to note is that the hexedecimal is not inserted as hexadecimal – its inserted as RGB! Yeah… I don’t know why either… if someone knows, please enlighten me in the comments below….

Mobile Safari Debug Console Breaks @Media Query

03 Jul 2012

Spent a lot of time spinning my wheels on this – in these cases you always think about whats changed since the last time your layout did what you wanted…and I backed up all the way to settings I enabled/disabled on the iPhone, and found the issue!

If you’re using an @media query like the following:

...
@media screen and (max-width:320px) and (orientation: portrait){
    /* your css here */
}
...

You will notice that it **breaks** when Mobile Safari’s debug console is enabled.

We can look into this a little further by using JavaScript to get the device’s reported width and we can infer the orientation from the number of degrees of rotation. To discover this information:

...
alert('width: ' + window.innerWidth + '\n orientation: ' + window. orientation);
...

Holding the iPhone in a portrait orientation with the debug console on we see the following values when reloading the test page:

  • width: 320
  • orientation: 0

The same test with the debug console off… is the same as with it on – there’s no smoking gun here as to why this is happening. The above @media query for unknown reasons is just plain broken with the debug console enabled!

Scaling Fixed Background Images

08 Jun 2012

I recently built a page template for a friend that required a static background image that scaled with the browser window while keeping the image’s aspect ratio intact. The challenge was more about getting it to display properly in IE 7 and 8. In the end there are a combination of approaches here – one for browsers that support “background-size:cover” and the other only for IE browsers below IE 9.

To begin, here’s the CSS-compliant bit – works in FF 3.6+, Safari 5+, IE 9+, and Chrome 5+.

First create two divs inside a blank HTML document. The first div will be the one responsible for the static back-ground image on our page, the second will be the wrapper for all of the page’s content. As you can see I’ve assigned ID’s to the two divs: “page-background” and “contentWrapper”.

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <title></title>
  </head>
  <body>
    <div id="pageBackground"></div>
    <div id="contentWrapper"></div>
  </body>
</html>

Next we want to start adding some CSS, lets start with the background. As the ID for the background is “pageBackground” lets add a STYLE tag to the page and define the DIV’s styling:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <title></title>
    <style type="text/css">
      #pageBackground {
	position:fixed;
	top:0;
	left:0;
	width:100%;
	height:100%;
	background-image:url(images/bg.jpg);
	background-position:50% 50%;
	background-repeat:no-repeat;
        -moz-background-size: cover;
	background-size:cover;
      }
    </style>
  </head>
  <body>
    <div id="pageBackground"></div>
    <div id="contentWrapper"></div>
  </body>
</html>

Breaking down the above CSS – “position:fixed” affixes the DIV to the viewing area outside of the document flow. The DIV will remain in its position regardless of page scrolling. “top” and “left” simply places the div to the upper left corner of the window and the “width” and “height” values of 100% ensure that the DIV stretches to fit the rest of the window.

Once the DIV is setup simply add the proper CSS for the image, including position (50% 50% places it in the center of the DIV), turn image repeating off and setting the “background-size” property to “cover” – this last item is what results in stretching the image to fill the page while maintaining the image’s aspect ratio. Some clipping may occur while the browser does this but it should be minor and is something to expect.

Finally, the “-moz-background-size” enables FireFox 3.6 support.

In order to appreciate the effect we should add a bit of content. The most important thing to realize here is that we will have to float our content-wrapping DIV over the background image so we will have to give it a higher z-index than the background.

Also you’ll see in the following code snippet that I’ve added some content to the “contentWrapper” and gave it a transparent background for extra effect.

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <title></title>
    <style type="text/css">
      #pageBackground {
	position:fixed;
	top:0;
	left:0;
	width:100%;
	height:100%;
	background-image:url(images/bg.jpg);
	background-position:50% 50%;
	background-repeat:no-repeat;
        -moz-background-size: cover;
	background-size:cover;
      }

      #contentWrapper {
	z-index:1;
	position:relative;
	width:900px;
	margin:60px auto 60px auto;
	padding:20px;
	color:#cccccc;
	background-color:#000000;
	-ms-filter:"progid:DXImageTransform.Microsoft.Alpha"(Opacity=80);
	filter: alpha(opacity=80);
	-moz-opacity: 0.80;
	opacity: 0.80;
      }
    </style>
  </head>
  <body>
    <div id="pageBackground"></div>
    <div id="contentWrapper" class="trans">
      <p style="height:600px;">top</p>
      <p style="height:600px;">middle</p>
      <p>bottom</p>
    </div>
  </body>
</html>

Cool, almost done – now for IE 7 and 8.

The “background-size” CSS property doesn’t exist in those browsers, so, the best that we can do is to use an image that is stretched to fill the page. Image scaling/stretching is an unfortunate consequence of this technique but is all that we have available to us.

So what we want to do is to use the above code/CSS for all capable browsers and then have a mechanism where we fall back to the stretched image approach for older IE browsers. My approach is to use conditional comments that only IE recognizes – all other browsers will ignore them.

The code is really pretty simple – we just add the conditional comment wrapping an image tag that we’ll add within the “pageBackground” DIV:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <title></title>
    <style type="text/css">
      #pageBackground {
	position:fixed;
	top:0;
	left:0;
	width:100%;
	height:100%;
	background-image:url(images/bg.jpg);
	background-position:50% 50%;
	background-repeat:no-repeat;
        -moz-background-size: cover;
	background-size:cover;
      }

      #contentWrapper {
	z-index:1;
	position:relative;
	width:900px;
	margin:60px auto 60px auto;
	padding:20px;
	color:#cccccc;
	background-color:#000000;
	-ms-filter:"progid:DXImageTransform.Microsoft.Alpha"(Opacity=80);
	filter: alpha(opacity=80);
	-moz-opacity: 0.80;
	opacity: 0.80;
      }
    </style>
  </head>
  <body>
    <div id="pageBackground">
      
    </div>
    <div id="contentWrapper" class="trans">
      <p style="height:600px;">top</p>
      <p style="height:600px;">middle</p>
      <p>bottom</p>
    </div>
  </body>
</html>

That’s it, pretty simple – I’m really not concerned with trying to get the same CSS effect in IE 7 or 8 and the above for my purposes is “good enough”. What we have is the image appearing only in IE versions less than 9 and its height and width stretch to fill the screen by virtue of the height and width of the image being set to 100%.