Jump to content
  • Checkout
  • Login
  • Get in touch

osCommerce

The e-commerce.

Combining all css into one


Recommended Posts

Hi,

https://gtmetrix.com/

advises to combine all .css files into one. Then I found that: https://manas.tungare.name/software/css-compression-in-php/ leading me there

https://gist.github.com/manastungare/2625128 

and then this came out

<?php $cssFiles = array(
  "ext/bootstrap/css/bootstrap.min.css",
  "custom.css",
  "user.css"
);
/**
 * Ideally, you wouldn't need to change any code beyond this point.
 */
$buffer = "";
foreach ($cssFiles as $cssFile) {
  $buffer .= file_get_contents($cssFile);
}
// Remove comments
$buffer = preg_replace('!/\*[^*]*\*+([^/][^*]*\*+)*/!', '', $buffer);
// Remove space after colons
//$buffer = str_replace(': ', ':', $buffer);
// Remove whitespace
//$buffer = str_replace(array("\r\n", "\r", "\n", "\t"), '', $buffer);
// Collapse adjacent spaces into a single space
//$buffer = ereg_replace(" {2,}", ' ',$buffer);
$buffer = preg_replace('/[\t\r\n]+/', '', $buffer);
$buffer = preg_replace('/[\s]{2,}/', ' ', $buffer);
$buffer = str_replace(': ', ':', $buffer);
// Remove spaces that might still be left where we know they aren't needed
$buffer = str_replace(array('} '), '}', $buffer);
$buffer = str_replace(array('{ '), '{', $buffer);
$buffer = str_replace(array('; '), ';', $buffer);
$buffer = str_replace(array(', '), ',', $buffer);
$buffer = str_replace(array(' }'), '}', $buffer);
$buffer = str_replace(array(' {'), '{', $buffer);
$buffer = str_replace(array(' ;'), ';', $buffer);
$buffer = str_replace(array(' ,'), ',', $buffer);
// Enable GZip encoding.
ob_start("ob_gzhandler");
// Enable caching
header('Cache-Control: public');
// Expire in one day
header('Expires: ' . gmdate('D, d M Y H:i:s', time() + 86400) . ' GMT');
// Set the correct MIME type, because Apache won't set it for us
header("Content-type: text/css");
// Write everything out
echo($buffer);
?>

Saved as css_compress.php loaded up to catalog root and included into template_top.php  with 

<link rel="stylesheet" type="text/css" media="screen, print, projection" href="css_compress.php"  />

instead of the single css files, only problem is now that glyphicon fonts (which i will get rid of anyway) gives 404.

Another question would be how to get css files of addons into that array also.

Any thoughts ideas?

Best regards

Christoph

Link to comment
Share on other sites

While combining (and minifying) CSS files can reduce load times, you have to be careful about a couple things:

  1. The order in which CSS entries will be seen (take priority) shouldn't change.
  2. Relative addresses (such as your glyphicon fonts) might change.

It also increases the burden on you when one of the component files changes, and you have to re-create the new combined file (especially if you have to tweak paths and update a new CSS file).

Link to comment
Share on other sites

Hi @MrPhil,

the css is rendered in the order of the files in the array, which means in this case user.css at last, just the normal behaviour.

Relative addresses a problem - yes true.

The file is rendered on the fly with adjustable caching, so there is no need to recreate manually after changing one of the css files.

Best regards

Christoph

Link to comment
Share on other sites

I can't tell exactly but it helps definitely https://testmysite.withgoogle.com/ I get 5 seconds on the index that was worse before. 

PageSpeed Score (95%) YSlow Score (81%) for desktop at gtmetrix.com. I think every little bit helps.

The coding effort, I'd really like to know if it was possible to get something like $oscTemplate->addBlock to add css to the array instead injecting into the page..

The simple wrong way is not so much of an effort -> comment out in module, add to array in css_compress.php.

Another thing I like about it: No more unminify for editing and then minifying again, I added bootstrap.css to the array instead of min as it makes no difference anymore.

Best regards

Christoph

Link to comment
Share on other sites

A very interesting read in the context IMHO: http://carlofontanos.com/get-a-perfect-score-of-100-on-google-pagespeed-insights/

Especially the part about "Get rid of render blocking scripts" might lead me to more attempts to load all js and css stuff in on place in the right order but no more before </head> except https://gist.github.com/carlo-fontanos/abc69dfea9d1e853c0e49fe509dbaa4b for template_top.php

The usage part in before mentioned  link part would go  into template botttom.

I will according to my limited abilities do simple evil core and addon code changes just for the proof of concept, and be happy to get help implementing this in a more like $oscTemplate->addBlock or $oscTemplate->getBlocks('footer_scripts') way. This could be a general way of injecting/adding javascript and css in a very elegant and speedy way in the future. 

Best regards

Christoph

Link to comment
Share on other sites

On the other hand, loading bootstrap from a cdn may save your first-time visitors loading most of the css if they already have it cached, and offer them a quicker load than you do anyway, depending on their location and that of your server.

I hope you have already addressed image sizes and are running a high php version, your database is well-maintained and your sessions are getting cleared down. If you are running lots of addons it may be the case that you're running too many separate queries to build your page and it may be that you need it optimising in some kind of super-addon that combines them and shares data - but I'm guessing. Any of these would make a much bigger difference than combining the css. BS is already minified and custom.css is as small as possible without losing legibility. You are saving a couple of server requests but not much data.

Contact me for work on updating existing stores - whether to Phoenix or the new osC when it's released.

Looking for a payment or shipping module? Maybe I've already done it.

Working on generalising bespoke solutions for Quickbooks integration, Easify integration and pay4later (DEKO) integration at 2.3.x

Link to comment
Share on other sites

Hi John,

nevertheless requests are time consuming too, ideally you would have one css an one js file to load non blocking - and it really depends how much blown up is the user css and how many and big additional css scripts are loaded by addons. 

At the moment I'm making experiments with the way css (in combination with initial post) and js is loaded mentioned in the post just above yours and it is really interesting - only blocking script is cookie.js ATM to be complained about by speed testing tools .

As for images: Im trying my best kraken.io  for compression, KissIT for thumbs, and the <picture> approach for logo and slides.

Which means: I want to look my logo not looking pixelated on hires devices but have smaller versions loaded on smaller devices.

Module for logo in header looks like this (hardcoded just for proof of concept):

<div id="storeLogo" class="col-sm-<?php echo $content_width; ?> storeLogo">
  <?php echo '<a href="' . tep_href_link('index.php') . '">  <picture>
  <source media="(min-width: 1000px)" srcset="images/store_logo.png">
  <source media="(min-width: 600px)" srcset="images/store_logo_900.png">
  <source media="(min-width: 400px)" srcset="images/store_logo_600.png">
   <source media="(min-width: 300px)" srcset="images/store_logo_400.png">' . tep_image('images/' . STORE_LOGO, STORE_NAME) . '</picture></a>'; ?>
</div>

Best regards

Christoph

Link to comment
Share on other sites

What I would like to do in the future, and this is something @wHiTeHaT and I discussed years ago at the start of the BS build is responsive images, but at the time I am pretty sure that neither of us had the time to spend on finding/coding a good image resizer. 

I would prefer to use srcset ( https://css-tricks.com/responsive-images-youre-just-changing-resolutions-use-srcset/ ), .  My general idea is for each image uploaded, creates 4 or 5 image sizes of it;

1 for XS
1 for SM
1 for MD
1 for LG
1 for XL

We then amend tep_image to output a srcset, and then relax in the knowledge that the sites images are awesome.  That would be my next step for optimisation...as I believe that would bring the most benefit to the most number of shopowners...

Link to comment
Share on other sites

11 minutes ago, beerbee said:

@burt yes. I asked @raiwa I think KissIT could do it.

 

I'll have a look and give it a try these days

Link to comment
Share on other sites

I like the v3 system for making images.  The script in the background/admin is decent.

The usage of the created images is not ideal.

Ideal:
<img srcset> the image output

Next best:
<picture>

Remember that v3 is built prior to the days of worrying about responsive and bandwidth.
So we could hybrid the two ideas?

 

 

Link to comment
Share on other sites

There my class to do that, work perfect (for me :) ).

<?php
/**
* 
* @license GNU Public License V2.0
* @version $Id:
*/

  namespace ClicShopping\Apps\Catalog\Products\Classes\ClicShoppingAdmin;

  class ImageResample {

    protected $image;
    protected $image_type;
    protected $filename;
    protected $height;
    protected $width;
    protected $size;
    protected $scale;
    protected $x;
    protected $y;

    public function __construct($filename = null){
      if(!empty($filename)){
        $this->load($filename);
      }
    }

    public function load($filename) {
      $image_info = getimagesize($filename);
      $this->image_type = $image_info[2];
      if( $this->image_type == IMAGETYPE_JPEG ) {
        $this->image = imagecreatefromjpeg($filename);
      } elseif( $this->image_type == IMAGETYPE_GIF ) {
        $this->image = imagecreatefromgif($filename);
      } elseif( $this->image_type == IMAGETYPE_PNG ) {
        $this->image = imagecreatefrompng($filename);
      } else {
        throw new Exception("The file you're trying to open is not supported");
      }

    }

    public function save($filename, $image_type=IMAGETYPE_PNG, $compression=100, $permissions=null) {
      if( $image_type == IMAGETYPE_JPEG ) {
        imagejpeg($this->image,$filename,$compression);
      } elseif( $image_type == IMAGETYPE_GIF ) {
        imagegif($this->image,$filename);
      } elseif( $image_type == IMAGETYPE_PNG ) {
        imagepng($this->image,$filename);
      }
      if( $permissions != null) {
        chmod($filename,$permissions);
      }
    }

    public function output($image_type=IMAGETYPE_JPEG, $quality = 80) {
      if( $image_type == IMAGETYPE_JPEG ) {
        header("Content-type: image/jpeg");
        imagejpeg($this->image, null, $quality);
      } elseif( $image_type == IMAGETYPE_GIF ) {
        header("Content-type: image/gif");
        imagegif($this->image);
      } elseif( $image_type == IMAGETYPE_PNG ) {
        header("Content-type: image/png");
        imagepng($this->image);
      }
    }

    public function getWidth() {
      return imagesx($this->image);
    }

    public function getHeight() {
      return imagesy($this->image);
    }

    public function resizeToHeight($height) {
      $ratio = $height / $this->getHeight();
      $width = $this->getWidth() * $ratio;
      $this->resize($width,$height);
    }

    public function resizeToWidth($width) {
      $ratio = $width / $this->getWidth();
      $height = $this->getHeight() * $ratio;
      $this->resize($width,$height);
    }

    public function square($size){
      $new_image = imagecreatetruecolor($size, $size);

      if($this->getWidth() > $this->getHeight()){
        $this->resizeToHeight($size);

        imagecolortransparent($new_image, imagecolorallocate($new_image, 0, 0, 0));
        imagealphablending($new_image, false);
        imagesavealpha($new_image, true);
        imagecopy($new_image, $this->image, 0, 0, ($this->getWidth() - $size) / 2, 0, $size, $size);
      } else {
        $this->resizeToWidth($size);

        imagecolortransparent($new_image, imagecolorallocate($new_image, 0, 0, 0));
        imagealphablending($new_image, false);
        imagesavealpha($new_image, true);
        imagecopy($new_image, $this->image, 0, 0, 0, ($this->getHeight() - $size) / 2, $size, $size);
      }

      $this->image = $new_image;
    }

    public function scale($scale) {
      $width = $this->getWidth() * $scale/100;
      $height = $this->getHeight() * $scale/100;
      $this->resize($width,$height);
    }

    public function resize($width,$height) {
      $new_image = imagecreatetruecolor($width, $height);

      imagecolortransparent($new_image, imagecolorallocate($new_image, 0, 0, 0));
      imagealphablending($new_image, false);
      imagesavealpha($new_image, true);

      imagecopyresampled($new_image, $this->image, 0, 0, 0, 0, $width, $height, $this->getWidth(), $this->getHeight());
      $this->image = $new_image;
    }

    public function cut($x, $y, $width, $height){
      $new_image = imagecreatetruecolor($width, $height);

      imagecolortransparent($new_image, imagecolorallocate($new_image, 0, 0, 0));
      imagealphablending($new_image, false);
      imagesavealpha($new_image, true);

      imagecopy($new_image, $this->image, 0, 0, $x, $y, $width, $height);

      $this->image = $new_image;
    }

    public function maxarea($width, $height = null){
      $height = $height ? $height : $width;

      if($this->getWidth() > $width){
        $this->resizeToWidth($width);
      }
      if($this->getHeight() > $height){
        $this->resizeToheight($height);
      }
    }

    public function cutFromCenter($width, $height){

      if($width < $this->getWidth() && $width > $height){
        $this->resizeToWidth($width);
      }
      if($height < $this->getHeight() && $width < $height){
        $this->resizeToHeight($height);
      }

      $x = ($this->getWidth() / 2) - ($width / 2);
      $y = ($this->getHeight() / 2) - ($height / 2);

      return $this->cut($x, $y, $width, $height);
    }

    public function maxareafill($width, $height, $red = 0, $green = 0, $blue = 0){
        $this->maxarea($width, $height);
        $new_image = imagecreatetruecolor($width, $height);
        $color_fill = imagecolorallocate($new_image, $red, $green, $blue);
        imagefill($new_image, 0, 0, $color_fill);
        imagecopyresampled($new_image, $this->image, floor(($width - $this->getWidth())/2), floor(($height-$this->getHeight())/2), 0, 0, $this->getWidth(), $this->getHeight(), $this->getWidth(), $this->getHeight());
        $this->image = $new_image;
    }

  }




  /* usage
  The first example below will load a file named picture.jpg resize it to 250 pixels wide and 400 pixels high and resave it as picture2.jpg
     $image = new SimpleImage();
     $image->load('picture.jpg');
     $image->resize(250,400);
     $image->save('picture2.jpg');

  If you want to resize to a specifed width but keep the dimensions ratio the same then the script can work out the required height for you, just use the resizeToWidth function.
     $image = new SimpleImage();
     $image->load('picture.jpg');
     $image->resizeToWidth(250);
     $image->save('picture2.jpg');

  You may wish to scale an image to a specified percentage like the following which will resize the image to 50% of its original width and height
     $image = new SimpleImage();
     $image->load('picture.jpg');
     $image->scale(50);
     $image->save('picture2.jpg');

  You can of course do more than one thing at once. The following example will create two new images with heights of 200 pixels and 500 pixels
     $image = new SimpleImage();
     $image->load('picture.jpg');
     $image->resizeToHeight(500);
     $image->save('picture2.jpg');
     $image->resizeToHeight(200);
     $image->save('picture3.jpg');

  The output function lets you output the image straight to the browser without having to save the file. Its useful for on the fly thumbnail generation


  <?php
     if( isset($_POST['submit']) ) {
        include('SimpleImage.php');
        $image = new SimpleImage();
        $image->load($_FILES['uploaded_image']['tmp_name']);
        $image->resizeToWidth(150);
        $image->output();
     } else {
  ?>

     <form action="upload.php" method="post" enctype="multipart/form-data">
        <input type="file" name="uploaded_image" />
        <input type="submit" name="submit" value="Upload" />
     </form>

  <?php
     }
  ?>

  */

 


Regards
-----------------------------------------
Loïc

Contact me by skype for business
Contact me @gyakutsuki for an answer on the forum

 

Link to comment
Share on other sites

I had some deeper look on the “srcset” tag and the posibility to combine it with a thumb generator like KissIt image thumbnail.

Here my conclusions:

-    KissIt Image thumb or any other thumb generator already produces optimized image sizes for the product listings/modules and boxes.

-    As the BS responsive design changes the layout depending on the device size, the required image resizing is already very reduced.

-    In a real store with small image, heading image and subcategory image sizes of 135 - 300 px, the maximum of browser downsizing is about 10-20% of the thumb-size.

-    This is due to the layout changing in the sense that the number of columns in the product listing gets reduced and the side boxes moved to the bottom. So the image sizes are kept in a narrow range which allows one thumb to fit already very well the effective required image sizes.

-    The only images which require very different sizes are images which use almost the entire viewport width. This is in a standard installation only the store logo if using col 6-12.

-    Other images could be banners or other additional promotional images if using the main content width or placed as a header/footer content module with col 6-12.

-    Only for these examples it would make sense to create different sized thumb images for different viewport sizes.

-    I doubt if it would need to be 5 different sizes, maybe 3 could be enough.

-    Another subject would be to serve retina devices with double resolution/sized thumbs which are not addressed for now by thumb generators.

-    This would mean to generally generate a second, double sized thumb and tag it by “srcset”.

-    Thumb generator should check if the required thumb size is notably bigger than 300px width, the usual max size of a small image used in product listings and boxes.

-    Only in that case it should create various versions, depending on the size of the original image. It doesn’t make sense to upsize neither to downsize below aprox. 300 px.

-    What has much influence on the image sizes is the jpg quality setting. There would be a point to improve KissIt image thumbnailer. Until now it uses a fixed quality setting for all thumbs. It could be improved to use the quality setting of the original jpg image always if it is lower than the general setting.

-    Also to take into consideration that the store owner uses accurate jpg quality settings for the kind of his images or an external service for image optimization.

-    Just an example: a 300 px square image can vary in size by different (Photoshop) quality settings:

  •    Quality 0 => 38.4kb
  •    Quality 4 => 44.3 kb
  •    Quality 6 => 50.9 kb
  •    Quality 9 => 58.6 kb
  •    Quality 12 => 79.9 kb

-    Some resampling in the range of 10-20% can save:

  •    Original image size 300px => 58.6 kb
  •    270 px => 56 kb
  •    240 px => 52.8 kb

-    Conclusion: optimizing the images by quality/compression has the same or more influence than 100% accurate size serving.

 

 

Link to comment
Share on other sites

Hi @raiwa,

thank you so much for looking into it.

But its not only the question of the amount of data requested but also if the browser has to render (consuming loading time)  the correct size and how close it to requested result. The closer you get to the result, the less will be complaints about rendering time to cover requested resolution. So my thoughts were going this way: If there is no definition for an image size like e.g. SMALL_IMAGE_WIDTH then <picture> should jump in providing relevant resolutions  for example if you'd say  picture on product_info  should take a percentive place on certain devices.  The less scaling work a browser has to do the better the speed. 

This might be be not so much a question of the user experience, but may be a question how the search engines might classify your site.

Best regards

Christoph

Link to comment
Share on other sites

Hi,

and now a little bit back to the original topic this thread was about.

I am totally not satisfied with something like $oscTemplate->getBlocks('footer_scripts'). This is confusing css with js all the way. In general there should be css loaded first  an then get to js scripts after. Everything should be non blocking. The trick is just mentioned before :

1
2
3
4
<style id="init-style">
*{color:#fff; border:0; background:none;}
img,button{display:none;}
</style>
is all the style gets loaded before everything else is present and looking beautiful through your css  and js efforts.
It would be much better to have a discerning loading of css and js than a mixed up one discerning footer and header.
 
Best regards
Christoph

 

Link to comment
Share on other sites

@beerbee Come up with something. Then once you have something that works, show it to someone like Gary @burt and see whether he thinks its worth the effort of coding into the BS version. Its difficult for people to uinderstand what you are trying to get across, so show them. You never know if its adopted into the core code you will have helped advanced the project forward.

REMEMBER BACKUP, BACKUP AND BACKUP

Link to comment
Share on other sites

1.  Try the script with .js turned off.  Many people have js off as default.

2.  <picture is used when you want to *force* a particular image to be rendered.  <srcset is used to reactively render.

3.  You add in database calls or logic calls in preference to simply hardcoding

It doesn't seem like a particularly valuable endeavour, but if you can make it work and prove it's better than what we have...I'm happy to consider core.

Link to comment
Share on other sites

I have

1) an image resizer that creates resized images on the fly when the requested size does not exist. Might have been KISS I'm not 100% sure - there are different ones, but essentially you get original image123.jpg and image123-120px.jpg, image123-360px.jpg kinda thing

2) adaptive images script to generate smaller / lightweight versions where appropriate - especially usefull for HD images also taking retina displays into account

http://www.adaptive-images.com/

I personally prefer the on-the-fly bit, makes it easy to make changes to image sizes without having to worry about generating all images in batch. I have been known to dump lots of images in directories, and use easypopulate to update the products_image field. A batch approach would need to be able to handle such a situation. You can not assume especially when building a new site that all images are uploaded one-by-one through an interface.

 

KEEP CALM AND CARRY ON

I do not use the responsive bootstrap version since i coded my responsive version earlier, but i have bought every 28d of code package to support burts effort and keep this forum alive (albeit more like on life support).

So if you are still here ? What are you waiting for ?!

 

Find the most frequent unique errors to fix:

grep "PHP" php_error_log.txt | sed "s/^.* PHP/PHP/g" |grep "line" |sort | uniq -c | sort -r > counterrors.txt

Link to comment
Share on other sites

  • 2 months later...

You forget to open the door and discuss about feeders, og image tags and a lot of outside requests. Inside image class usage (like Kiss Image) very limited and dont give 100% access of the cache file. (If cache file not generated then give back nothing from an outside direct url call (404). Transponder mechanism missing. Oscommerce images can not serve directly with a special presized format.

@bruyndoncx gives a better example.

Facebook required minimum 600x600 px images in feeders. I think the same with Twitter but not the same resolution required and we can not use optimal images in html emails. So everywhere are minimum requirements not only in viewports.

Js solutions limited and can be able to use only for client browsers.

Image Transponder could be run on 2 different way
1. use built-in classes and adapt global hook mechanism (I use it for email pixel)
https://github.com/osCommerce/oscommerce2/blob/de9e922377cbfd0678c9e4b9e8eb51123f3e230a/catalog/includes/classes/hooks.php#L20
(includes/hooks/shop/global - like an API entrance. Link: https://yourshop.com/?action=resizeimage&image=iamgename&size=240)
Disadvantages here all codebase running for an image serving

      $this->register('global');
      $this->register('global');

2. use an independent primitive cache system like adaptive-images.com (https://github.com/Gergely/oscom_responsiveimages)
Advantages here is that this use less resources and images could serve from another domain

These mechanism ensure to give back resized images.

So I am ready to coding something because this solution is missing and oscommerce can not serve well presized images. KISS Image is really stupid even if I use it now.

:blink:
osCommerce based shop owner with minimal design and focused on background works. When the less is more.
Email managment with tracking pixel, package managment for shipping, stock management, warehouse managment with bar code reader, parcel shops management on 3000 pickup points without local store.

Link to comment
Share on other sites

On 18-11-2017 at 3:11 PM, imusorka said:

@bruyndoncx I actually like the sound of the second approach. Is the installation as straightforward as they mention or are modifications required for it to work with osC? Or maybe this is massively outdated by today's web standards? 

it is "deadeasy"

KEEP CALM AND CARRY ON

I do not use the responsive bootstrap version since i coded my responsive version earlier, but i have bought every 28d of code package to support burts effort and keep this forum alive (albeit more like on life support).

So if you are still here ? What are you waiting for ?!

 

Find the most frequent unique errors to fix:

grep "PHP" php_error_log.txt | sed "s/^.* PHP/PHP/g" |grep "line" |sort | uniq -c | sort -r > counterrors.txt

Link to comment
Share on other sites

@tgely ping me again in 3 months ... overwhelmed with work (store shutdown and warehouse move, another part time job with office move, and private house move ...) no time to tinker now.

KEEP CALM AND CARRY ON

I do not use the responsive bootstrap version since i coded my responsive version earlier, but i have bought every 28d of code package to support burts effort and keep this forum alive (albeit more like on life support).

So if you are still here ? What are you waiting for ?!

 

Find the most frequent unique errors to fix:

grep "PHP" php_error_log.txt | sed "s/^.* PHP/PHP/g" |grep "line" |sort | uniq -c | sort -r > counterrors.txt

Link to comment
Share on other sites

Archived

This topic is now archived and is closed to further replies.

×
×
  • Create New...