Gregory's Blog

Demonstrating the benefits of the new webp image format

The next generation webp format is one of the most important image formats to have come along in the last several years.

My first impression of webp images was 'meh'. I read articles on the next generation webp image format. The articles claim that webp images are about 26% smaller than their png equivalents. What I read was impressive, but not just enough to delve into learning how to use them.

I only started playing around with webp to chase a better Google lighthouse score. Google knocked my 'Best Practices' score down a couple of notches, and I finally decided to investigate using them. I'm glad that I did! I did not find a 26% improvement with my own images, but a 95% improvement in size than the identical .png images that I had created. Want proof? I'll demonstrate my own results...

Please take a look at my Greensock animation introducing the next version of Galaxie Blog at https://gregoryalexander.com/blog/index.cfm/2019/9/16/Galaxie-Blog-135-Animated-Blurb. If you're using a modern browser, you should notice that this intense graphical scene renders rather quickly. On a vain note- I also hope that you find the scollmagic scene to be pretty...

The scrollmagic scene that you are looking at should deliver images in the webp format if your browser supports them. If the browser does not support webp, png's will be rendered instead. I'll go over the code later on, but right now I will compare the image sizes to show you the improvements. I'll provide the link and size of each actual image in the grid below so you can take a look yourself.

I created the original source images using Adobe Illustrator, and exported them to png's using the 'save as legacy web' option. To create the web images, I took the png images that I had created and used Irfanview to export the png as a webp. Take a look at the size reduction in the table below.

The entire payload of all of the combined webp images is 90% less than one of the actual png images! With this type of extreme size reduction we can vastly improve our loading time, or we can now use full quality images in animated sequences like this!

I am also using webp instead of jpg images. Here the improvements are not as as substantial, but I have shaved about 10-15% of the size of the jpg images.

How to get started with webp images.

Server side code

Currently, with the exception of Safari- most modern HTML5 capable browsers support webp images. To determine if a browser supports the next generation format is relatively easy. Thankfully, nearly all modern browsers will include webp support in the header if the browser supports the webp next gen image. Here is the ColdFusion script that I developed.

view plain about
1<!--- Determine if the http accept header contains webp. The getHttpRequestData().headers is a structure and we are targetting the accept element in the array. Note: nearly all modern browsers will include this if the browser supports the webp next gen image. --->
2<cfset acceptHeader = getHttpRequestData().headers["accept"]>
3<!--- Does the header accept webp? --->
4<cfif findNoCase("webp", acceptHeader) gt 0>
5    <cfset clientAcceptsWebP = true>
6<cfelse>
7    <cfset clientAcceptsWebP = false>
8</cfif>

A hybrid server side and client side approach

Most web servers support the webp image format as well. However, on web servers that are not current, you may need to add the webp mime type. Consult with your ISP or server documentation to find out how to add webp mime type on your server. Here is the function that I developed to test webp support on the server and save the result as a persistent application variable. You will have to create a small webp image and upload to your own server for this to work (see headerBodyDivider.webp below).

view plain about
1<!--- Determine if the webP mime type is set up on the server. --->
2    <cffunction name="serverSupportsWebP" access="public" returntype="boolean" output="yes">
3        <!--- Note: we need to eliminate https from the root URL if it exists. I ran into errors trying this with https (a cryptic certificate error). --->
4        <cfset thisUrl = replaceNoCase(application.rootUrl, "https", "http")>
5        <!--- The headerBodyDivider image is a tiny .webp image (around 1k). We are going to read this, and if it was found and the mime type is correct, we will assumed that the mime type is correct. Otherwise, we will determine that the server does not support the webp mime type. --->
6        <cfhttp method="get" URL="#thisUrl#/images/divider/headerBodyDivider.webp">
7            
8        <!--- Was the webp image found? --->
9        <cfif cfhttp.mimeType contains 'webp'>
10            <cfset webp = true>
11        <cfelse>
12            <cfset webp = false>
13        </cfif>
14        <!--- Return it. --->
15        <cfreturn webp>
16    </cffunction>

In my code, I either use the server side logic above to test both the server and the client for webp support, or I use a hybrid approach where I save the result of the serverSupportsWebP server side function and test for support using javascript on the client like so:

view plain about
1<script>
2        // WebP support detection. Revised a script found on stack overflow: https://stackoverflow.com/questions/5573096/detecting-webp-support. It is the quickest loading script to determine webP that I have found so far.
3        function webPImageSupport() {
4            // Detemine if the webp mime type is on the server. This is saved as a ColdFusion application variable.
5            var serverSupportsWebP = <cfoutput>#application.serverSupportsWebP#</cfoutput>;
6         var elem = document.createElement('canvas');
7            
8         if (serverSupportsWebP && !!(elem.getContext && elem.getContext('2d'))) {
9         // Is able to get WebP representation?
10         return elem.toDataURL('image/webp').indexOf('data:image/webp') == 0;
11         }
12         // webp is not supported on older browsers such as IE.
13         return false;
14        }
15    </script>

Using either approach is valid. However, I typically use server side code to set the paths of my images, and only use the hybrid approach (using the script above) when I am manipulating the DOM with javascript.

Example server side logic to set the image extension

I personally set the default image to be png or jpg, and only change it if both the client and the server support webp:

view plain about
1<!--- Determine if the http accept header contains webp. The getHttpRequestData().headers is a structure and we are targetting the accept element in the array. Note: nearly all modern browsers will include this if the browser supports the webp next gen image. --->
2    <cfset acceptHeader = getHttpRequestData().headers["accept"]>
3    <!--- Does the header accept webp? --->
4    <cfif findNoCase("webp", acceptHeader) gt 0>
5        <cfset clientAcceptsWebP = true>
6    <cfelse>
7        <cfset clientAcceptsWebP = false>
8    </cfif>
9        
10    <!--- Logic to determine if the server has the necessary webp mime type was done in the application.cfc template. We will use the application.serverSupportsWebP variable that the mime type is installed on the server. Of course, both the client and the server need to support webp images before we can deliver them.--->
11    <cfif application.serverSupportsWebP and clientAcceptsWebP>
12        <cfset webpImageSupported = true>
13    <cfelse>
14        <cfset webpImageSupported = false>
15    </cfif>
16        
17    <cfif webpImageSupported>
18        <!--- Overwrite the headerBodyDividerImage var and change the extension to .webp --->
19        <cfset headerBodyDividerImage = replaceNoCase(headerBodyDividerImage, '.png', '.webp')>
20    </cfif>

Tips

When saving webp images, don't use the Adobe Photoshop or Illustrator plugin's. There are two of them as of today, and neither of them work well. Instead, just create your images and save them as jpg or png, and use Irfanview 64 to open and save them as a webp image. I have tried many approaches, and this method has proven to be the most reliable.

Thanks for reading, and happy coding!

Gregory

This entry was posted on September 17, 2019 at 12:31 AM and has received 174 views.

There are currently 0 comments. Download attachment.

Introducing Galaxie Blog 1.35 with a new Parallax Scene


Galaxie Blog is a Next Generation Blog Platform

Galaxie Blog is the most beautiful and functional open sourced ColdFusion blog in the world.

galaxie Parallax Image 1
galaxie Parallax Image 2
galaxie Parallax Image 3
galaxie Parallax Image 4
galaxie Parallax Image 5
galaxie Parallax Image 6

Galaxie Blog is fast....

Galaxie Blog consistently performs above 80% in Google lighthouse scores...

For comparison, the industry average performance score of the top ecommerce sites is is around 22%

Galaxie Blog is Accessible...

Galaxie Blog has a perfect 100% 'Accessibility' Google Score

The industry average sites is around 60%.

Galaxie Blog has a perfect 100% 'Best Practices' Google Score

Galaxie Blog uses all of the 'Best Practices' suggested by Google.

The industry average score is about 61%

Galaxie Blog has a perfect 'Search Engine Opimization (SEO)' score.

Having a perfect SEO ensures that search engines will be able to collect and promote your content.

Galaxie Blog allows you to enforce SSL....

Blog owners can specify whether to enforce SSL. If SSL is enforced, all port 80 traffic will be a automatically redirected to an encryted port.

Galaxie Blog delivers next generation media content...

Galaxy Blog now delivers webp images if both the client and the server support the new webp format.

If webp is not supported, Galaxy Blog will fallback and deliver images using tradional web formats.

Improved Entry Image Support

Administrators can easilly add images to their entries by clicking on a button and selecting an image. Galaxie Blog will take care of the rest.

To improve performance, Galaxie Blog will only render the image once it comes into the user's viewport.

Improved Social Media Sharing

Galaxie Blog now prominently displays social media icons to share your social media at the bottom of each individual blog entry.

You can use dynamic includes within an entry using xml.

This very GSAP scene that you're looking at now is acheived using a dynamic cfinclude.

Goals for the next version...

Overhaul the original database and add 'Disqus' integration.

Galaxie Blog is still using the original BlogCfc database and it must be updated. If feasable, I will add Disqus comment integration.

 

This entry was posted on September 16, 2019 at 12:50 PM and has received 144 views.

There are currently 0 comments.

Related Entries

Google Lighthouse Metrics for Galaxie Blog Version 1.35



I am finally done chasing a nearly perfect Google lighthouse score and have released Galaxie Blog version 1.35. I have a perfect score for 3 out of 4 categories, and the performance score generally falls between 70 and 90. Performance: 90%1 Accessibility: 100% Best Practices: 100%2 and SEO (Search Engine Optimization): 100%

Attaining this score was not easy- especially for a large blog site. This is major accomplishment.

I spent over a month working on all aspects of the site. The google audit checklist is exhaustive. For example, I am deferring all non essential resources until page load, lazy loading the images and media, using next generation image formats (webp)3 and networking protocols (http/2) if possible, have no errors written to the console, etc, etc.

I will write up several blog entries in the next couple of weeks to highlight some of my approaches.

1 Performance results can vary considerably.
2 Attained with the commercial Kendo license. The open source Kendo Best Practices score is at 86 due to the Kendo embedded jQuery library. According to Telerik, this should be fixed in the near future.
3 Webp images are only served when both the client and the server supports them. When webp is not supported, Galaxie Blog will fallback to traditional image protocols. I will write up an article on this in the near future.

This entry was posted on September 13, 2019 at 12:29 PM and has received 159 views.

There are currently 0 comments. Download attachment.

Related Entries

How to speed up your site with lazy loading

Lazy loading is a process where you defer loading your non-essential scripts and media until after the page loads. With lazy loading, you don't load everything at once, however, you defer the loading of images and scripts until they are actually needed. This is essential if you're trying to improve the load time of your site.

In this technical article, I will show you the process that I used in order to vastly improve the performance of this blog site.

Let's take a second to visually see what lazy loading is by taking a look at my own site. If you navigate to my main blog at www.gregoryalexander.com/blog and slowly scroll down, you will notice that the images do not load until you reach them. When the image is in the viewport, you will notice an image that looks like it is fading in. I am not loading these images when the page loads, but am waiting for you to scroll down before loading them. In order to achieve this effect, we need to have a library that uses the intersection observer API .

This is how the 'big boy's', like Facebook do it. Follow along and I can walk you through in order to do it on your own.

There are a multitude of different lazy loading libraries out there. I have tried a handful of these libraries, but settled on defer.js by shinsenter. My requirements are more extensive than usual. Along with the my requirements to lazy load my blog media, I needed to defer the loading of Kendo UI and other extensive libraries such as the Green Sock Animation Platform (GSAP). These libraries need to have a strict order to which libraries are loaded that they depend upon.

I had some issues with a handful of other libraries, but defer.js allowed me to achieve what I need.

Kendo UI needs to have jQuery loaded prior to the extensive Kendo UI scripts, and Kendo UI requires loading a large javascript library along with common .css files, a .less based css file that is required by the users chosen theme, and mobile css for mobile clients. GSAP also has several dependencies. I'll go through the process that I used to properly defer these scripts until the page loads defer.js below. At the end of this technical article, I'll discuss how I lazy loaded the blog media as well.

Before we do anything, we need to insert the defer.js code in the head section of your document:

view plain about
1//* Script to defer script resources. See https://appseeds.net/defer.js/demo.html.
2// @shinsenter/defer.js */

3!function(e,o,t,n,i,r){function c(e,t){r?n(e,t||32):i.push(e,t)}function f(e,t,n,i){return t&&o.getElementById(t)||(i=o.createElement(e||'SCRIPT'),t&&(i.id=t),n&&(i.onload=n),o.head.appendChild(i)),i||{}}r=/p/.test(o.readyState),e.addEventListener('on'+t in e?t:'load',function(){for(r=t;i[0];)c(i.shift(),i.shift())}),c._=f,e.defer=c,e.deferscript=function(t,n,e,i){c(function(e){f(0,n,i).src=t},e)}}(this,document,'pageshow',setTimeout,[]),function(u,n){var a='IntersectionObserver',d='src',l='lazied',h='data-',p=h+l,y='load',m='forEach',r='appendChild',b='getAttribute',c=n.head,g=Function(),v=u.defer||g,f=v._||g;function I(e,t){return[].slice.call((t||n).querySelectorAll(e))}function e(s){return function(e,t,o,r,c,f){v(function(n,t){function i(n){!1!==(r||g).call(n,n)&&(I('SOURCE',n)[m](i),(f||['srcset',d,'style'])[m](function(e,t){(t=n[b](h+e))&&(n[e]=t)}),y in n&&n[y]()),n.className+=' '+(o||l)}t=a in u?(n=new u[a](function(e){e[m](function(e,t){e.isIntersecting&&(t=e.target)&&(n.unobserve(t),i(t))})},c)).observe.bind(n):i,I(e||s+'['+h+d+']:not(['+p+'])')[m](function(e){e[b](p)||(e.setAttribute(p,s),t(e))})},t)}}function t(){v(function(t,n,i,o){t=[].concat(I((i='script[type=deferjs]')+':not('+(o='[async]')+')'),I(i+o)),function e(){if(0!=t){for(o in n=f(),(i=t.shift()).parentNode.removeChild(i),i.removeAttribute('type'),i)'string'==typeof i[o]&&n[o]!=i[o]&&(n[o]=i[o]);n[d]&&!n.hasAttribute('async')?(n.onload=n.onerror=e,c[r](n)):(c[r](n),v(e,.1))}}()},4)}t(),u.deferstyle=function(t,n,e,i){v(function(e){(e=f('LINK',n,i)).rel='stylesheet',e.href=t},e)},u.deferimg=e('IMG'),u.deferiframe=e('IFRAME'),v.all=t}(this,document);

This script is short, and it can be either placed inline, or you can grab the code via CDN at https://github.com/shinsenter/defer.js/.

Defer Kendo UI.

Kendo UI requires loading the following files- in this order:
  1. jQuery (not deferred)
  2. kendoUiCore.js (or kendoUiAll if you're using your own license).
  3. The kendoUi common .css file.
  4. The kendoUi theme .css file.
  5. And the kendoUi mobile .css file

Here is how I achieved this in actual code. This code also needs to be placed in the head section of the page underneath the defer.js code:

view plain about
1// Load the javascript files.
2<script src="/common/libs/kendo/js/jquery.min.js"></script>
3<script type="deferjs" src="/common/libs/kendo/js/kendo.all.min.js"></script>
4// Load the style sheets
5<script type="deferjs">
6// Kendo common css. Note: Material black and office 365 themes require a different stylesheet. These are specified in the theme settings.
7$('head').append( $('&lt;link rel="stylesheet" type="text/css" />
').attr('href', '/common/libs/kendo/styles/kendo.common.min.css') );
8// Less based theme css files.
9$('head').append( $('&lt;link rel="stylesheet" type="text/css" />').attr('href', '/common/libs/kendo/styles/kendo.silver.min.css') );
10// Mobile less based theme file.
11$('head').append( $('&lt;link rel="stylesheet" type="text/css" />').attr('href', '/common/libs/kendo/styles/kendo.silver.mobile.min.css') );
12</script>

Note the deferjs in the script type. This is a keyword used by the defer.js library to defer these scripts until page load. Here, all of the Kendo UI resources are deferred other than the jQuery library.

Defer GSAP and ScrollMagic resources.

GSAP is an amazing library if you're interested in cutting edge animation effects. I use GSAP and ScrollMagic to provide for my parallax effects. See the entry Introducing Galaxie Blog for an example of a parallax effect.

My requirements to load GSAP and SrollMagic are:
  1. Load the tweenMax javascript library
  2. Load scrollMagic
  3. Load the main GSAP library
  4. Load the scrollToPlugin library
  5. And load my GSAP debugging script

All of the GSAP resources will be deferred until page load.
Here is the code:

view plain about
1<script type="deferjs" src="/blog/common/libs/greenSock/src/uncompressed/TweenMax.js"></script>
2<script type="deferjs" src="/blog/common/libs/scrollMagic/scrollmagic/uncompressed/ScrollMagic.js"></script>
3<script type="deferjs" src="/blog/common/libs/scrollMagic/scrollmagic/uncompressed/plugins/animation.gsap.js"></script>
4<script type="deferjs" src="/blog/common/libs/greenSock/src/uncompressed/plugins/ScrollToPlugin.js"></script>
5<script type="deferjs" src="/blog/common/libs/scrollMagic/scrollmagic/uncompressed/plugins/debug.addIndicators.js"></script>

Note: typically, the GSAP libraries are loaded at the end of the page, however, this did not work for me. I found that these files must be loaded in the head section.

Lazy loading media files.

My open source Galaxie Blog allows blog owners to upload pictures and media that show up on the top of every blog post. However, on the main blog page, this necessitates the client to download quite a lot of extra data. In order to achieve a decent page load time I had to figure out a way to delay the loading of this media. I also wanted to convey to the reader that something was happening and alert them with a subtle css effect when a new picture is loaded. Here is the defer.js approach:

CSS:

view plain about
1/* Lazy loading image classes */
2/* Initially hide the element with zero opacity */
3.fade {
4transition: opacity 500ms ease-in-out;
5opacity: 0;
6}
7
8/* Show it with the 'shown' class */
9.fade.shown {
10opacity: 1;
11background: 0 0;
12}


Javascript:
view plain about
1// Lazy loading images and media.
2// Callback function to add the 'shown' class into the element when it is loaded
3var media_loaded = function (media) {
4media.className += ' shown';
5}
6// Then call the deferimg and deferiframe methods
7deferimg('img.fade', 300, 'lazied', media_loaded);
8deferiframe('iframe.fade', 300, 'lazied', media_loaded);

Place the script and the CSS anywhere in your document as long as it is above the media that you're about to lazy load. Place the following javascript at the end of the page:

view plain about
1// Lazy load the images.
2deferimg('img.fade', 100, 'lazied', function(img) {
3img.onload = function() {
4img.className+=' shown';
5}
6});

Finally, include your image like so:

<img class="fade" data-src="https://gregoryalexander.com/blog/enclosures/8_31.png" alt="">

I'll quickly try to explain what is going on here. If you look carefully, you'll notice that the "src" tag is missing from the above image. The media does not show at first due to the src tag that is missing, and the opacity setting that is initially set to zero. When the defer.js library notices that the user has scrolled to the viewport where the image resides, defer.js takes the string found in the data-src tag and automatically builds the src dynamically. When the image is loaded to the client, the CSS briefly fades in.

You can use the same approach to defer and lazy load pretty much anything. If you're interested, you can dig into the meaty details by looking at my source code, or checking out the excellent defer.js demo.

This entry was posted on September 9, 2019 at 3:29 AM and has received 198 views.

There are currently 2 comments. Download attachment.   Show Comments

Galaxie Blog status update



I have not been blogging for awhile now... and had wanted to wait to post anything until I got out another incremental version of the Blog before posting- but I am still working on it. Ben Nadel, Charlie Arehart, Wil Genovese, and other major bloggers have the ColdFusion blog world covered- and I like developing. I'm also a reluctant blogger. But, I digress- I wanted to write up a quick status update...

One of you out there (there has got to be one of you out there, right!?) may have noticed that I used the term 'Galaxie Blog', not 'Gregory's Blog', right? Why yes, that's right! I renamed it to Galaxie Blog! This blog has not had much attention, and it may be due to the perception that this is my own personal blog, which it's not. It's a major free open source ColdFusion project needing some love and attention!

I had multiple conversations with Charlie Areheard, and one of his suggestions was to change the name of this blog to 'Galaxie Blog'. And after some thought- I agree with him, thus the name change...

I have been working on a lot of things other than the easy branding change...

The new version, still in development, is 2-3x faster than this site. Google lighthouse is scoring the new development version between 70 and 90 percent on performance. The performance range is all over the place. I could get a 72 score, run it again, and get a 98 two seconds later (which is shown in the photo above). However, I got consistent results between 70 and 90. For comparison, the industry average performance score of the top ecommerce sites is is around 22% (https://www.practicalecommerce.com/70-leading-retailers-lighthouse-scores-revealed).

The Google lighthouse accessibility score is consistent at 100%. The average score of the top e-commerce sites is around 60%.

SEO (search engine optimization) score is still at 100%, but I made a deeper dive into current SEO practices and made several other improvements.

Best Practices is at 86%. The only major hits here were not using the http2 protocol (my ISP does not yet allow http2 calls yet, or the score would be much higher). Industry average is about 61%.

I am also quite close to being able to having Galaxie Blog (it feels weird writing that!) as a Progressive Web App. A Progressive Web App is a web application that is installable. It will still run when the user does not have an internet connection (via cache) and then send push notifications when the client is back online. However, I am still not sure if I will be able to finish this in this particular version.

I have a lot more stuff that I have made improvements upon, and I should have this new version out relatively soon... please bear with me.

Suggestions and comments would be quite welcomed!

Gregory

Lame PS Hello? Hello? Is anyone out there! Please feel free to say hello!

This entry was posted on September 1, 2019 at 1:00 AM and has received 306 views.

There are currently 0 comments. Download attachment.

My biggest SEO problem....

Content... who in the hell is going to read anything about ColdFusion and Telerik Kendo integration anyway!? Sigh....

This entry was posted on September 1, 2019 at 12:50 AM and has received 243 views.

There are currently 0 comments.

Introducing Galaxie Blog


Introducing Galaxie Blog

Galaxie Blog is a free open source ColdFusion based blog.

It is intended to be the most beautiful and functional open sourced ColdFusion based blog in the world.

delicateArch Parallax Image 1
delicateArch Parallax Image 2
delicateArch Parallax Image 3
delicateArch Parallax Image 4
delicateArch Parallax Image 5
delicateArch Parallax Image 6

Stunning Mobile Interface...

Galaxie Blog is a responsive website that offers nearly identical functionality for both desktop and mobile devices.

Galaxie Blog is Eminently Themeable

Galaxie Blog has dozens of professionally designed pre-defined themes.

Changing the look and feel of you blog does not require any coding, you can use web based interfaces to perfectly adjust each theme.

Versatile Post Formats...

Add podcasts, thumbnails, images, and enclosures. Blog entries support using inline .css, scripts, and HTML.

Add Engaging Content and Special Effects...

Includes a HTML5 media player as well as a Flash player to allow users to add various media.

Galaxie Blog also has built in support for animations using the Green Sock Animation Platform.

Display Your Code...

Easilly display your code by wrapping your posts with 'code' tags. The code will be displayed and will be automatically adjusted to match your theme.

Interact With Your Users...

Galaxie Blog allows users to add comments and use their own gravatar.

Captcha support and blog moderation capabilities are included.

Share Your Content...

Allow readers to share your blog content with built-in social media sharing.

Users can subscribe to your blog or subscribe to a selected post. Galaxie Blog also can share your content with various communities via RSS feeds.

Organize And Find Your Posts...

Categories and tag support are built-in. You can also associate your blog entries and related posts.

Find your posts using a search engine at the top of the site. Posts are also automatically displayed by date and can be selected using a calendar control.

Optimized for Search Engines

Galaxie Blog is SEO friendly and has a 100% google SEO score.

The Future of Galaxie Blog...

I intend using Galaxie Blog for my own personal blog, and it is a key component of my own personal portfolio.

I am adding capabilities to use a rich editor within a mobile interface to quickly share my personal photography while out in the field.

 

This entry was posted on July 15, 2019 at 10:15 PM and has received 737 views.

There are currently 3 comments.   Show Comments

Using top: auto will not work when vertically aligning text within multiple block level elements.

Using top: auto, margin: auto, margin-top: -50%, etc, will not work when vertically aligning text within multiple block level elements. The problem with these css declarations in block level elements is that the values would be calculated as zero when they are calculated relative to the width of outer blocks.

CSS2 specifies that block level elements are stacked vertically from top to bottom in normal flow.

If you only have one block level element, the the top and bottom margins will be zero and these declarations will be calculated correctly. For example, the following code will work to vertically align the text:

view plain about
1.slide#slide02 .wrapper {
2    top: auto;
3    left: 5%;
4    text-align: left;
5    padding: 0;
6}

However, if you have more than one block level element in the same flow, the code will not work as the auto margins will not be calculated correctly.

When you're using multiple block level elements, use absolute positioned elements to vertically align the text like so:

view plain about
1.slide#slide02 .wrapper {
2    position: absolute;
3    top: 50%;
4    display: table-cell;
5    vertical-align: middle;
6    left: 5%;
7    text-align: left;
8    padding: 0;
9}

This entry was posted on July 12, 2019 at 2:18 PM and has received 299 views.

There are currently 0 comments. Download attachment.

Fine tuning your theme with Kendo Theme Builder

Galaxie Blog is built from scratch to be fully themeable, and using the Kendo theme builder in addition with the built in theme settings allows you to have full control over the look and feel of your own theme.

It was my goal to have dozens of themes and interfaces built into Galaxie Blog that would help to allow you to build a theme that you love- or to get you 95% of the way. If the theme does not perfectly match the look and feel of your site, using the Kendo UI Theme builder should be able to take you the rest of the way there.

The Kendo UI Theme Builder enables you to modify Kendo UI themes to perfectly match the look and feel of your website or application. Without scripting or using HTML, you will have complete control over the design of the buttons, backgrounds, windows, widgets, such as the calendar and HTML5 media player, dialog's, and even alternating color schemes with an easy to use interface.

To modify the .less based theme file, first preview and choose one of Galaxie Blog default themes that comes close to the look and feel of your site. The base Kendo theme can be found by either looking at the URL, or on the settings page in the administrative interface.



Once you jot down the name of your desired theme, head over to the Kendo UI Theme Builder.

On the far left of the interface, click on the Kendo theme that you have chosen. Here, you have hundreds of different options to choose from, but first start out by changing the accent and widget base colors. You'll notice that any changes that you have made will be shown to you on the right immediately. The first dozen or settings are important, you don't need to check out the series colors, most of these are for various charts. Investigate and set everything as you would like, and when you're ready, click on the download button at the top of the page.


After downloading the files and extracting the .zip file, you should see 3 different files: kendo.custom.css: kendo.custom.dataviz.json, and kendo.custom.less. Upload the two .css and .less files to your server. I suggest saving these two files in a new folder named 'myStyles' in the /common/libs/kendoCore directory, but you can save them anywhere on your server that you would like.
Note: you don't need to do anything with the .json file.



After uploading the file to your server, jot down the path that you uploaded the kendo.custom.css file to, and head over to Galaxie Blog administrative interface and click on the settings link.

In the settings page, look for the Customize Kendo Themes section. Click on the modify themes checkbox, and type in the path and file name that you uploaded the kendo.custom.css file to. Don't worry about the mobile theme location setting, the mobile settings should work with the custom .css file. Leave the rest of the forms as is, and click on the save button at the bottom of the page. You may have to iterate through the same steps again if you want to continue to dink around with the look and feel of the theme.



Happy Theming!

This entry was posted on June 28, 2019 at 6:42 PM and has received 360 views.

There are currently 0 comments. Download attachment.

Using a dynamic variable to set a dynamic path variable when dropping a cookie

ColdFusion sometimes drives me a bit wonky when I try to set a dynamic variable inside a tag. Most ColdFusion tags support embedded dynamic variables, but quite a few tags don't support this. Probably the most frustrating issue is when you want to use a dynamic variable to extend an application in a sub-folder using two or more application.cfc templates. It seems that every other time I do this I slap my head and think 'Oops! it's time to set up proxy extensions', sigh... but this frustrating issue requires a very long blog entry for a different day. Back to my point...

If you try to use a dynamic variable using a cfcookie tag, you will get the following nasty error:

view plain about
1<cfcookie name="isAdmin" value="true" path="#application.baseUrl#" expires="never">

Attribute validation error for tag CFCOOKIE. It has an invalid attribute combination: expires,name,path,value. Possible combinations are: Required attributes: 'name'. Optional attributes: 'domain,encodevalue,expires,httponly,preservecase,secure,value'. Required attributes: 'domain,name,path'. Optional attributes: 'encodevalue,expires,httponly,preservecase,secure,value'.

To get around this, simply use the cookie scope instead in order to set the dynamic path value.

view plain about
1<!--- Using the cfcookie tag does not work with dynamic vars in the path. --->
2<cfset cookie.isAdmin = { value="true", path="#application.baseUrl#", expires=30 }>

Both cfcookie and the cookie scope do the same thing, send a cookie to the client, but at least the cookie scope allows you to embed dynamic variables for in the path name.

This entry was posted on June 28, 2019 at 12:11 PM and has received 306 views.

There are currently 0 comments. Download attachment.




Footer Logo

Your input and contributions are welcomed!

If you have an idea, BlogCfc based code, or a theme that you have built using this site that you want to share, please contribute by making a post here or share it by contacting us! This community can only thrive if we continue to work together.

Images and Photography:

Gregory Alexander either owns the copyright, or has the rights to use, all images and photographs on the site. If an image is not part of the "Galaxie Blog" open sourced distribution package, and instead is part of a personal blog post or a comment, please contact us and the author of the post or comment to obtain permission if you would like to use a personal image or photograph found on this site.

Credits:

Portions of Galaxie Blog are powered on the server side by BlogCfc, an open source blog developed by Raymond Camden. Revitalizing BlogCfc was a part of my orginal inspiration that prompted me to design this site. Some of the major open source contributers to BlogCfc include:

  1. Peter Farrell: the author of 'Lyla Captcha' that is used on this blog.
  2. Pete Freitag: the author of the 'ColdFish' code formatter that is also used on this blog.

Version:

Galaxie Blog Version 1.35 September 6 2019