Sunday, July 17, 2016

Relative paths regarding images

The problem

I run into this problem on occasion and unfortunately it is more complicated than it sounds. Really I don't understand why the frameworks responsible make this so damn complicated. I am basically going on a guess here and I think it is a combination between the web servers (not so much) and web browser engines along with the W3C's HTML standards. The problem I am driving up to is using relative paths for statically located images and other resources on your website. 

Really this comes down to the folder structure of your site, but I don't think the folder structure of your site should have to suffer from this problem. I think you should be allowed to have as many nested folders as you want and come up with crazy structures - it still doesn't explain why in all the years of web this problem has not be solved in a simple way.

Everything is best explained with an example.

Assumptions

  • For argument's sake let's focus on images and forget about JS and CSS for now. 
  • Let's call the root of my site http://www.CoolSite.com/
  • Let's say that the root of my site is physically located at C:\CoolSite\
  • Let's say I have a folder where I keep all of my images, 
    • Physically located here: C:\CoolSite\images\
    • Virtually located here: http://www.CoolSite.com/images/
  • I have an image in the images folder named "loading.gif":
    • C:\CoolSite\images\loading.gif
    • http://www.CoolSite.com/images/loading.gif
  • I have a page that references loading.gif at the root of my site
    • C:\CoolSite\test.htm
    • http://www.CoolSite.com/test.htm
As is - the above works perfectly fine. However, someone comes along and says: 
I need to use loading.gif in a new feature that is going to be located in a different folder called "FakeDir1".

Nested directory one

  • FakeDir1, contains its own test.htm which references loading.gif
    • C:\CoolSite\FakeDir1\test.htm
    • http://www.CoolSite.com/FakeDir1/test.htm
Well now... this causes a problem. Usually people think it is just fine to use relative pathing, but I beg to differ. Microsoft 95% solved this problem by introducing a special MS convention that uses the tilde character. I am not going to get into that, because it is not relevant to plain, simple, HTML. Therefore how does one normally handle this right off the bat? Like so:
  • FakeDir1, contains its own test.htm which references loading.gif
    • C:\CoolSite\FakeDir1\test.htm
    • http://www.CoolSite.com/FakeDir1/test.htm
    • For your image source attribute: ../images/loading.gif
And thus, this reads "Go down one directory relative to where I am right now and then back up into a folder that is hopefully located there called images and you shall land upon loading.gif" - oh great, this solves the problem... but then someone comes along and says:
"I need to use loading.gif in a new feature that is going to be located inside of FakeDire1 named "FakeDir2".

Nested directory two

Sigh... okay... so this forces us one more time to do this:
  • FakeDir2, contains its own test.htm which references loading.gif
    • C:\CoolSite\FakeDir1\FakeDir2\test.htm
    • http://www.CoolSite.com/FakeDir1/FakeDir2/test.htm
    • For your image source attribute: ../../images/loading.gif
Oh wonderful, there is a recurring pattern which is not being taken care of automatically - this is never good. It means copy/paste and creating brittle structures. Below is a visual representation of what was just done. Ignore the URL, it is the same idea as what was explained above, I was explaining this to a coworker of mine at work.

Nested directory N

Root example equivalent to http://www.CoolSite.com/test.htm

http://www.CoolSite.com/FakeDir1/test.htm - up one directory

http://www.CoolSite.com/FakeDir1/FakeDir2/test.htm - up two directories

http://www.CoolSite.com/FakeDir1/FakeDir2/FakeDir3/test.htm - up three directories
If you have been following the examples from top to bottom you will notice that the top line's image source never breaks. The image always renders. You are probably thinking that - that's the way to go. Well you would be wrong again because that stops working as soon as you want to place your site inside of a virtual directory because this syntax "/images/loading.gif" reads "Go to the root of this site, locate a folder called images and find a file called loading.gif".

Therefore to be very clear the following will break this: "/images/loading.gif"

If I take the source of "http://CoolSite.com/" and point it to the following virtual directory "http://CoolSite.com/VirtualDirectory1/" then you will have the following configuration for the root page:
  • C:\CoolSite\test.htm
  • C:\CoolSite\images\loading.gif
  • http://www.CoolSite.com/VirtualDirectory1/test.htm
  • http://www.CoolSite.com/VirtualDirectory1/images/loading.gif
  • For your image source attribute: 
    • ./images/loading.gif - will work
    • /images/loading.gif - will NOT work because it will be looking here "http://www.CoolSite.com/images/loading.gif" which doesn't virtually exist

The solutions

These are the solutions I could find for this, none of them are very good, but it's what I could come up with to deal with these situations.

  1. Make sure when you are setting up your sites, you are not using Virtual Directories for your sites because then you cannot use this syntax "/images/loading.gif" for example. As indicated already above, that syntax goes to the base site. You have to ask yourself "Why am I using a virtual directory?" Usually the answer is "I don't know how to setup multiple websites on the same server." - well, I don't mean to be harsh, but that isn't an excuse - go learn how to do it. I will eventually write an article on this, but the information is readily available. Stop using Virtual Directories unless you know why you are using them.
  2. Use a media server, image server or Content Delivery Network (CDN) so that your URLs never change, then folder depth doesn't matter anymore. However, problems come with this and they are:
    1. Remember to update your content when something has changed
    2. Development can become a problem
    3. Now your content is separated from your site, this isn't generally a good idea unless you are a massive site
  3. This is a pretty bad solution, but it will work. Copy your images relative to things that need them that way the pathing doesn't matter ever. Examples:
    1. http://www.CoolSite.com/Images/loading.gif
    2. http://www.CoolSite.com/test.htm - if you use "/images/loading.gif" - this will work
    3. http://www.CoolSite.com/VirtualDirectory1/test.htm - if you use "/images/loading.gif" - this will work
    4. However, just like the CDN you have to remember to update that images folder. The way I am showing it is a clean way of doing it. A crappier way to do it is to copy the images folder into each FakeDir and update the pathing to use "./images/loading.gif" then you can make sure to update every images folder always. Scripts can accomplish this, but why go this far?

Conclusion

The point is that there are various ways to deal with this, but realistically there isn't a good way to deal with it. Your best defense is a good architecture and directory structure. Lean on a framework for help where it makes sense, but not to the point where it makes your site suffer.

No comments:

Post a Comment