0

ASP.NET Image tag and Accessibility

by volkanuzun 25. February 2010 22:50

If you are working at a company that is following Section 508 Guidelines, and building websites that are compliant with this guidelines, you should know that asp.net image tag has a bug. Let’s start with the definition of the problem first:

If you are using the images at your website purely fore decorative, then the images should have empty alt attribute such as: <img src=”…” alt=”” />.  Let’s assume now that you are using <asp:Image control to display the decorative image such as:

<asp:Image id="someDecoration" runat="server" AlternateText="" ImageSrc="..."/>
 

You will be suprised to see that  the code that this control generates is not accessible, because when the AlternateText is empty, the control does not generate the empty alt attribute but simply ignore it. If you put a space in between the quotes after the AlternateText attribute, this time screen reader will read the image alt attribute and confuse the user.
If you change the asp:Image control into html image with runat=”server attribute for whatever reason, it still has the same bug that it wont render the empty alt attribute.

The solution I found for this problem is, to use alt attribute with <asp:Image control. The control does not recognize this attribute (asp:image control uses AlternateText to render alt attribute), and as it does not recognize the attribute, it does not touch it :).

A simple hack, but works great :)

Tags:

Acccessibiliy

0

What the heck is System.BadImageFormatException?

by volkanuzun 31. January 2010 19:29

I am new to using Sqllite for my unit tests, and I was getting all bunch of errors, one of the most popular one is :

"System.BadImageFormatException: Could not load file or assembly 
'System.Data.SQLite, Version=1.0.65.0, Culture=neutral,
PublicKeyToken=db937bc2d44ff139'

or one of its dependencies. An attempt was made to load a program with

Culture=neutral, PublicKeyToken=db937bc2d44ff139'

 

I am using Visual Studio 2010 beta 2, and Nunit for my unit tests; so most of the time I am blaming Visual Studio 2010 beta 2 version for any error I am getting, as it is a beta version!
When I googled it, I found a few different suggestions; but as in most of the Google answers, those suggested solutions work for some people apparently but not for me :). One of the suggestions actually work for me, and it is the reason for this mini blog post. Here is my information about my development environment:
I am using Resharper V5.0 beta,and Visual Studio 2010 beta 2.  Apperently Resharper 5.0 is running the unit tests in 32bit mode. And my development environment including the Sqllite is all 64 bits, so I need to use 64 bit version of Nunit, however Resharper is not doing this.

My next step was, I ran Nunit-gui to run my unit tests, and hoped that everything was working for now, and guess what it wasn’t :). This time it was my fault,as I did not run the 64 bit of the Nunit gui. So as a next step this time I ran the Nunit-guiX64.exe and ran my tests, and everything is working fine :)

Tags: ,

0

Action’s parameters and Selection Decision

by volkanuzun 21. December 2009 22:38

    When you have an action, with an overloaded version of it in the controller, its parameters are not used to to decide the selection.

Let’s assume you have a form, and user clicks on the submit button, to send the form to the server. The action that renders the view for the get request is: Register(), and the action that receives the request is Register(FormCollection collection) similar to something like this:

public ViewResult Register()
{
    //do some prep for the view
    return View();
}

public ViewResult Register(FormCollection collection)
{
    //do something with the collection
   // either return a view, or redirect to another action
}

I didn’t put any action selector on purpose; to prove my point. If you run this page, and try to call /Register you can get an error. Basically the framework is complaining that it can’t pick which Register() action it should call to respond /Register. You may think that because the second Register() action has a parameter, it should not be picked for a get request; however it is not the case :)

Let’s look at the MVC source code to see how an action is executed. If you open the source code, and check the Controller.cs file, around line 162, you will this function:

 

   1:    protected override void ExecuteCore() {
   2:              TempData.Load(ControllerContext, TempDataProvider);
   3:   
   4:              try {
   5:                  string actionName = RouteData.
GetRequiredString("action");
   6:                  if (!ActionInvoker.InvokeAction
(ControllerContext, actionName)) {
   7:                      HandleUnknownAction(actionName);
   8:                  }
   9:              }
  10:              finally {
  11:                  TempData.Save(ControllerContext, TempDataProvider);
  12:              }
  13:          }

 

Look carefully at line 6. This where the action is invoked, now we have to dig in more, and see what is happening inside ActionInvoker.InvokeAction method. This method is doing 1 thing that is important for the topic of this blog:

 ActionDescriptor actionDescriptor = FindAction(controllerContext,
controllerDescriptor, actionName);
 
 

It is trying to find the action to execute, given the action name, and the controller name. It adds the results into a list of methodinfo. Here is it:

   public MethodInfo FindActionMethod(ControllerContext controllerContext, 
string actionName) { List<MethodInfo> methodsMatchingName = GetMatchingAliasedMethods
(controllerContext, actionName); methodsMatchingName.AddRange(NonAliasedMethods[actionName]); List<MethodInfo> finalMethods = RunSelectionFilters(
controllerContext, methodsMatchingName); switch (finalMethods.Count) { case 0: return null; case 1: return finalMethods[0]; default: throw CreateAmbiguousMatchException(finalMethods,
actionName); } }


After it adds the methods that it finds to the list, it runs the RunSelectionFilters function to eliminate the methods. After the eliminations, if it has more than 1 method left in the list, it throws the exception; which you see when you call /Register. As you can see the parameters of the action has nothing to do with the selection.
One way to help the framework to pick the right action is to use SelectionFilters; as you can see from the code above, FindActionMethod() calls the RunSelectionFilter() to eliminate the actions.

If you use AcceptVerbs selection filter to differentiate between the two Register function, framework won’t be complaining as before; so this is one way of doing it right:

[AcceptVerbs(HttpVerbs.Get)]
public ViewResult Register()
{
    //do some prep for the view
    return View();
}

[AcceptVerbs(HttpVerbs.Post)]
public ViewResult Register(FormCollection collection)
{
    //do something with the collection
   // either return a view, or redirect to another action
}
 

This time, when there is a get request, RunSelectionFilter() will eliminate Register(FormCollection collection), as it has the AcceptVerbs post selecttionfilter.

I am still walking through the ASP.NET MVC source code, and really enjoying the way the developers wrote it; it is really fun to read it.

Have fun :)

Tags:

MVC

0

MVC Case Sensitivity & Action Names & NonAction Attribute

by volkanuzun 6. December 2009 02:44

Today, it was the first class of our free ASP.NET MVC course. I was talking about URLs not being case sensitive. So that for example if you have the request “Home/About” this goes to HomeController and About action, as well as hOmE/AbOUT is going to the same controller and same action method.
One of the students ask me, what will happen if we have 2 about action methods in the same controller with different cases such as:

public class HomeController:Controller
{
....
    public ViewResult About()
    {
        return View();
    }

    public ViewResult aBOut()
    {
        return View();
    }
}

If you write the code above, and try to run the app, and call Home/About, here is the error message you will get:

image

The framework can’t determine which ‘about’ function to call, and throws the exception telling that the call is ambiguous. Of course one way to fix this problem is to change the action name. If for some reason you don’t want to change the action name, and one of these function is not an action, then you can decorate this non action method with NonAction attribute. Example:

[NonAction]
public ActionResult aBOut()
{
   return View();
}

So now this function is not anymore an action method that will handle the web requests. What is NonAction attribute?
It is an attribute that derives from ActionMethodSelectorAttribute. When you derive from this attribute you can override IsValidForRequest function, and return false, to refuse to serve as an action. If you check the MVC source code, here is the code for NonAction attribute:

[AttributeUsage(AttributeTargets.Method, 
AllowMultiple = false, Inherited = true)] public sealed class NonActionAttribute : ActionMethodSelectorAttribute { public override bool IsValidForRequest(ControllerContext
controllerContext, MethodInfo methodInfo) { return false; } }
 

This code is refusing to act as a request. So you can use this NonAction attribute on any of your public functions inside a controller to make them not web accessible.

Tags:

MVC

2

Why Controllers should have a default constructor?

by volkanuzun 13. November 2009 03:21

    I am still in the journey of exploring MVC source code.  Yesterday, I wrote about controllers and why they need “Controller” suffix. Today, I will try to find out in the code, why does a controller need a default constructor. First of all, what is default constructor?
You can check wikipedia for its complete definition; but basically a default constructor is a constructor that has no parameters. If there is no other constructors in the code, compiler puts a default constructor for you in the code. You don’t believe me? Here is a simple class:

public class Person
    {
        public string FirstName { get; set; }
        public string LastName { get; set; }
    }


This class does not have any type of constructors, so the compiler put a default constructor for us. compile the project, check the assembly with either reflector or ildasm tool. You will see the default constructor in your compiled code (besides some other stuff):

image 
.ctor() is the default constructor that the compiler added for us, when we did not supply any constructor. So what happens when we add a constructor that takes a parameter but no default constructor:

public class Person
    {
        public string FirstName { get; set; }
        public string LastName { get; set; }

        public Person(string FirstName)
        {
            this.FirstName = FirstName;
        }
    }

We now have a constructor that takes the FirstName as a parameter, and we don’t have a default constructor. This time if you check the assembly again, you will find:

image

You see that, the constructor .ctor does take 1 parameter, and there is no default constructor for us. This means when you want to create a new instance of Person, you can NOT use parameter less constructor such as: Person p = new Person();  You have to call it with a parameter.
So far, this is basic C#, where is MVC section? Here you are:

When a request comes into the MVC, we saw that the framework finds the controller first. Inside the DefaultControllerFactory (if you downloaded the source code, it is in DefaultControllerFactory.cs line # 83), an instance of the controller is being created to process the request. Here is the code from the controller factory:

 protected internal virtual IController GetControllerInstance
(Type controllerType) { // some code is here... try { return (IController)Activator.CreateInstance(controllerType); } // some other code is here...

Activator.CreateInstance is used to create an instance of the controller. Let’s see MSDN for Activator.CreateInstance:

“CreateInstance(Type)    Creates an instance of the specified type using that type's default constructor.” So Activator.CreateInstance(controllerType) will create an instance of the specified controller using the controller’s default constructor. This is the main reason controllers should have a constructor, as DefaultControllerFactory creates the controller by using its default constructor.  Luckily if we don’t have a default constructor, the framework will throw an exception at runtime when it is trying to generate a new instance (I wish we could have compile time error).  The error you will have is very self explanatory.

image 

The framework is even showing us the exact location that throws the exception. So we need to supply a default constructor if we have defined constructors with parameters.
Why would you have a constructor in your controller that takes parameter if the framework does not call it? For 2 simple reasons:

  1. Unit Testing: You want to unit test your controller, and by supplying some values in the constructor you can swap the dependencies with some other implementations that you have control of.
  2. You want to do inversion of control. Basically if you have a class, and your class depends on some other entities (such as your controller needs a class to communicate with database, or a logger class to log the errors), it shouldn’t be a task of your controller to create an instance of this classes that it depends. The classes  should be instantiated and given to your controller ready to use.

 

Let’s see an example again, assume you have a DatabaseLogger class which derives from ILogger interface and sends the logged message to the database:

public interface ILogger
{
    void SendMessage(string Message);
}

public class DatabaseLogger: ILogger
{
    public void SendMessage(string Message)
   {
      // some code to write the message to the database


Our HomeController needs the DatabaseLogger class to send some messages. One way  of doing this is to put the instantiation inside the default controller such as:

public class HomeController:Controller
{
    private ILogger logger;

    public HomeController():base(new DatabaseLogger())
    {     
    }

    public HomeController(ILogger logger)
    {
        this.logger = logger;
    }
}

There are 2 constructors in this controller. The second one that has a parameter, sets the controller’s dependency to the passed in logger interface. The default constructor is creating an instance of DatabaseLogger and passing this to the second constructor. With this technique here we can unit test our controller as the second constructor gives us the ability to swap the ILogger with an object that we can control.  However, if you look at the default constructor, the controller is creating the class that it has the dependency on. It should be passed the depedency ready to use. In this simple example maybe the benefit is not obvious however think that DatabaseLogger() needs some construction parameters that will setup the database connection string, and maybe to read the database connection string, you have some other dependencies such as a configuration file reader. Now your homecontroller has to supply all these settings to create the DatabaseLogger. This is too much now, this is where you need to use dependency injection such as Castle Windsor, StructureMap, Ninject etc…

This will be another story :)

Tags: ,

MVC

1

Why Controllers should have a “Controller” Suffix?

by volkanuzun 12. November 2009 07:06

   If you are programming with ASP.NET MVC, you know that the controller’s should have a suffix of “Controller” such as “HomeController”. You may also know that this is how DefaultControllerFactory works.
Let’s look into the technical details. I will skip some unrelated facts, but we will check the MVC source code, and modify it a little. Please go to CodePlex and download the MVC source code.
When a request comes into IIS (Microsoft’s web server application), IIS first checks the request, then the MVCRouteHandler is called (assuming this is an MVC request). The MVCRouteHandler creates an instance of  MvcHandler by passing the request context. You can check out the code in the MVCRouteHandler.cs file.

protected virtual IHttpHandler GetHttpHandler(RequestContext requestContext) {
            return new MvcHandler(requestContext);
        }


After creating the instance, ProcessRequest (from MVCHandler) is invoked and HttpContext is passed as the parameter. The ProcessRequest function is below:

 protected internal virtual void ProcessRequest(HttpContextBase httpContext) {
            AddVersionHeader(httpContext);

            // Get the controller type
            string controllerName = RequestContext.RouteData.
GetRequiredString("controller"); // Instantiate the controller and call Execute IControllerFactory factory = ControllerBuilder.
GetControllerFactory(); IController controller = factory.CreateController(RequestContext,
controllerName);
.... some other calls


As you can see, this function calls the GetControllerFactory() method, to get the ControllerFactory. If you haven’t registered a new ControllerFactory, this function returns the DefaultControllerFactory. The next call in ProcessRequest function is CreateController.  So let’s see what is happening in the DefaultControllerFactory’s CreateController function.

public virtual IController CreateController(RequestContext requestContext, 
string controllerName) { if (requestContext == null) { throw new ArgumentNullException("requestContext"); } if (String.IsNullOrEmpty(controllerName)) { throw new ArgumentException(
MvcResources.Common_NullOrEmpty, "controllerName"); } RequestContext = requestContext; Type controllerType = GetControllerType(controllerName); IController controller = GetControllerInstance(controllerType); return controller; }


This function after checking requestContext, and controllerName against null values, calls GetControllerType. Here is what GetControllerType does:

protected internal virtual Type GetControllerType(string controllerName) {
            if (String.IsNullOrEmpty(controllerName)) {
                throw new ArgumentException(MvcResources.Common_NullOrEmpty,
"controllerName"); } // first search in the current route's namespace collection object routeNamespacesObj; Type match; match = GetControllerTypeWithinNamespaces
(controllerName, nsHash); if (match != null) { return match; } } }


This is not the whole function but a piece of it.

Again after checking some values against null, it is calling the main function which is GetControllerTypeWithinNamespaces.  I am sure you are already bored from one function call to another function call :) however, I will be writing more about the MVC infrastructure, so it is good to show them. So one more time, let’s look at the GetControllerTypeWithinNamespace function.

The first thing this function does is to call: ControllerTypeCache.EnsureInitialized(BuildManager). This will load all the controllers and cache them, so that the next time a controller is needed, the framework doesn’t have to find and load the controllers. This is a simple yet pretty important function.

 public void EnsureInitialized(IBuildManager buildManager) {
     if (_cache == null) {
          lock (_lockObj) {
            if (_cache == null) {
              List<Type> controllerTypes = GetAllControllerTypes(buildManager);
              var groupedByName = controllerTypes.GroupBy(           
      t => t.Name.Substring(0, t.Name.Length - "Controller".Length),
                            StringComparer.OrdinalIgnoreCase);
       _cache = groupedByName.ToDictionary(
                            g => g.Key,
                            g => g.ToLookup(t => t.Namespace ?? 
String.Empty, StringComparer.OrdinalIgnoreCase), StringComparer.OrdinalIgnoreCase); } } } }


As you can see this function caches the controllers after loading them. The _cache variable that is used in this function is a Dictionary<string,ILookup<string,type>>. So basically the framework loads the controllers into a cache. The function that loads the controllers is GetAllControllerTypes. It loads all the assemblies, iterating through them by calling a function: IsControllerType. This is why, this needs to be cached, as you don’t want to load all the assemblies and check if they are controllers. So this IsControllerType function is the reason why we have to add suffix “Controller” to our controllers:

 internal static bool IsControllerType(Type t) {
            return
                t != null &&
                t.IsPublic &&
                t.Name.EndsWith("Controller", 
                StringComparison.OrdinalIgnoreCase) &&
                !t.IsAbstract &&
                typeof(IController).IsAssignableFrom(t);
        }


This function is checking if the passed in controller, has a suffix of “Controller” or not. If it does, it returns true, and GetAllControllerTypes adds this controller to the list, and returns the list of controllers.

The call goes back to EnsureInitialized which strips out the Controller suffix, and adds it into the cache. Let’s assume we want our controllers to have suffix of “Volkan” ; what do we need to do?

First you have to change the IsControllerType so that it checks .EndsWith(“Volkan”) not “Controller”. This will let the <controllerName>Volkan controllers to be added to the list. But this is not enough, the next thing we have to do is, go back to EnsureInitialized and change the stripping part from t.Name.Length - "Controller".Length to t.Name.Length - "Volkan".Length .

Finally you have to put the “Volkan” suffix to your controllers, and now this becomes a valid controller:

      public class HomeVolkan : Controller{

 

Enjoy your time debugging the MVC code!

Tags: ,

MVC

1

Sql injection & Sanitizing Database & Triggers

by volkanuzun 5. November 2009 19:48

    In one of the web applications we have at my work, there is a sql injection problem. Unfortunately the web application is very old, programmed with classic asp, the company does not support it anymore. We have the source code for the web application as it is classic asp however; the code is not documented, and the hit points to the database is all over, so I can’t just simply go to one location in the source, and fix it. 
   The first thing I have to do after we are hit, is to stop the attacks, so after reporting the Ip address of the attacker to the related departments, I knew I couldn’t fix the problem in the code; so I added a trigger to the database, that will check the inserted data; and if found a <script command simply rollback. Here is a sample trigger that does this:

   1:  CREATE  TRIGGER [dbo].[checkNewsForScriptandIFrameAttach]
   2:  ON [dbo].[news]
   3:  AFTER INSERT, UPDATE
   4:  AS
   5:  IF @@ROWCOUNT=0
   6:  begin
   7:      RETURN
   8:  END
   9:  declare @headline varchar(350)
  10:   
  11:  set @headline = (select headline from inserted)
  12:   
  13:  IF(CHARINDEX('<iframe',@headline))>0
  14:  BEGIN
  15:      ROLLBACK TRANSACTION
  16:  END
  17:   
  18:  IF(CHARINDEX('<script',@headline))>0
  19:  BEGIN
  20:      ROLLBACK TRANSACTION
  21:  END

This is a trigger that will run after the insert and update sql commands on the database. What it does is, to get the column value from the inserted table (this is a special table that sql server uses, before it actually writes the value to the actual table), and checks if the inserted column has <iframe or <script tags. If there is any, then rollback the transaction and don’t write the new values to the actual table but wipe them out.

So the next step is to sanitize the table that is already hit, I could use TSQL for this, but I decided to use LINQ as I can log the operations and do some other things while I am sanitizing the table. I wrote this small console application:

   1:      NewsDBDataContext db = new NewsDBDataContext();
   2:   
   3:      var scriptCode = "<script src=http://www.somefckrcode></script>";
   4:   
   5:      var news = db.News;
   6:      foreach (var news in news
   7:      {
   8:         news.headline = news.headline.Replace(scriptCode,String.Empty);
   9:         db.SubmitChanges();
  10:         //some log operations here
  11:      }

All this code does is to replace the script tag with empty string. Of cource I can query the database, and bring in only the records that has the scriptCode value injected; however in my case all the rows has it, so I simply get all the records, and iterate through all of them.

I ran this application, and got the error from sql “Value will be truncated….”; it wasn’t a good error message; as it wasn’t really telling me anything. But quickly I figured out that the problem was the trigger, the trigger was on, and my code was checking the script and updating it, however trigger was throwing an error; I disabled my trigger, then ran the application, everything worked perfectly fine, and enabled the trigger back again.

One more note on this, the number of rows that  I am updating is around 9000; the update took around 5 minutes; when I replace the headline.Replace with a regular expression replace, the code took less than a minute :)

Tags:

0

Web Accessibility 103 – Forms

by volkanuzun 23. October 2009 07:30

    When a user using screen reader, visits a page that has forms, the screen reader enters into this special mode called “Forms Mode”.

The screen reader tries to match the form elements with corresponding labels. Such as if you have input element (except button), the screen reader will try to find a <label> element or a title attribute.  When it finds the matching label tag for the input element, it will read the input element and the label together so it will make sense to the user.
Let’s assume you have the code below:

<form>
<p>First name: <input type='text' id='fname' name='lname'></p>
...

As you can see we didn’t put the label tag for the text. When the screen reader hits this part; it will say “First Name” and it will say textbox, but no details about the textbox. A sighted person can visually make the connection between the First Name and the textbox; however a user who needs screen reader may not be able connect this 2 elements.

The right way to do this is :

<form>
<p><label for='fname'>First name:</label><input type='text' 
id='fname' name='fname'/>


What we did is to add a label for the input. The id we write for label for has to match with the id of the input element.
Now the screen reader has enough information to make a relation with the input element and what this is for. When the screen reader hits this place, now it will say input text for first name, and the user will understand the form elements better.

What if we can’t put a label for the form element? Such as we have a 3 textboxes that will make up a date. Below is the code:

Date of Birth: <input type='text' id='month' name='month' maxlength='2'>
 <input type='text' id='day' name='day' maxlength='2'>
 <input type='text' id='year' name='year' maxlength='4'>


We can not have 3 labels for each of the input element, as it will look ugly, but also we want to make this form accessible to all users. So what do we do? Now we can use title attribute of the form element to help the screen reader.  Here is the fixed form:

Date of Birth:<input type='text' id='month' name='month' maxlength='2'
               title='Date of Birth Month'/>
<input type='text' id='day' name='day' maxlength='2'
               title='Date of Birth Day'/>
<input type='text' id='year' name='year' maxlength='4'
               title='Date of Birth Year'/>


This time we put title attribute to the input elements, to help the screen reader understanding what these input elements are about. You should prefer label for whenever possible and use titles if labels are not applicable. There is also a nice benefit when you use labels, whenever the user clicks on the label text, the browser will move the cursor to the corresponding form element, think how useful this is with checkboxes.

Another things to be watch out when making forms accessible is the required fields, their location, error message etc. Assume you have a form where user can create an account for himself, and this form is asking first name, last name and email. All these 3 fields are required, and if the form fails the validation (such as the email is not valid, first name is left blank etc), you put an error message right below the form.  Now when a user who uses a screen reader, fill this form, and submits the form; if he makes a mistake filling the form element or writing his email wrong, he may be confused. After the form submission the screen reader will the read form again, so user knows he is still on the filling form page, after reading the input elements, the screen reader will read the error message. The user has to listen to the form that he filled in again before he listens the error message, after listening the error message tab back into the form element to fix it. Sighted person can easily skip the form, and concentrate on the error message, however a blind person has to listen the form again. If you move the error message right above the form, now whenever the form fails to validate, user know what has failed, and can tab into the form element to fix it.

As you can see forms requires little more special attention to make it accessible however it is still pretty simple.

0

Web Accessibility 102 – Skip Navigation

by volkanuzun 3. October 2009 05:24

    Yesterday I talked about Web Accessibility 101 - Images, and today I will be talking about skip navigation.
    If you have a repetitive navigation on your website, then you should supply a method to your users to skip these navigation links. First let’s try to understand why the people using assistive technology needs a skip navigation.
Let’s assume your user is a visually impaired person, and he uses a screen reader. Your website has probably either an upper menu, left menu or right menu. The first time visually impaired person visit the page, he listens the pages (screen reader reads the page), including the navigation section of your page. He clicks or selects one the links on the menu, and new page has the navigation of course, and the user listens the navigation again before he gets a chance to listen the content. So every time the user selects a link on the site, he has to listen the same navigation again and again. 
    You have 2 options to help your user to reach the content without listening the navigation all the time. One method is the old method which is putting a skip navigation link on your page as the first item. This link could be 1 pixel image link on the top-left of your screen that takes the user to the body part of the page. This also helps the people that visits your page with their mobile phones as they can skip everything to the content.
You don’t have to put only 1 skip navigation link on your site, you can put as many as you want. Actually in one of my projects, I had to use 3 skip navigations. The first one was to jump from the upper company menu to the department site content, the second link is to skip the department site navigation, and the third one is to skip the filter options on the page.
An example code for the skip navigation could be like this:

<a href="#mainContent"><img src="/images/skipNav.jpg"
alt="Skip to Main Content" ></a>


and at the beginning of the your content part:

<a name="#mainContent"/>


Another solution is using header on your page which will a topic of another blog post as there is more than skipping the navigation with headers, however a small tip is : if you use h1,h2..h6 in your pages, users can easily navigate on your page using these headers.

Have fun making your site accessible :)

Tags:

Web Accessibility, Section 508 Guidelines

0

Web Accessibility 101 – Images

by volkanuzun 2. October 2009 03:38

    If you work for any federal agency, or you sell a product to a product to a federal agency, this product must be complained with Section 508 Guidelines. Although Section 508 guidelines covers a lot of stuff, I will be talking about Web Accessibility. So I will assume you either work for federal agencies (universities, colleges …), or you sell products to these organizations, or simply you want to target everybody as your potential client and you want to be accessible. There is so many things when it comes to accessibility, so in this post I will only cover images.

    When a visually impaired person visits your site, he may not see the images, or he may disable the images, he may be using a screen reader to surf your site. You have to accommodate his needs, and give him a chance to visit and understand your site as much as you accommodate a sighted person. How will you achieve this?

  • Your images that have a content should have an alt attribute that explains what  the image is.
    Bad Example: <img src=”/images/acrobat.gif”> or <img src=”/images/acrobat.gif” alt=”acrobat”/>
    Good Example: <img src=”/images/acrobat.gif” alt=”Acrobat Pdf Logo”/>
    As you can see not having an alt attribute and  a bad description in the alt attribute is not accessible.
    Put yourself in the shoes of a blind user, who is visiting your site with a screen reader, this will help to improve your common sense.
  • If you are using the images for decorative purposes, you should put an empty alt attribute to the image tag.
    Bad Example: <img arc=”/images/background.gif”/>
    Good Example: <img src=”/images/background.gif” alt=””/>
  • If you have a complex description for your image, that you can not possibly use alt attribute to describe the context, use longdesc attribute of the image. For example if your image is a graph that shows the monthly sales, for different departments, it will be very difficult to explain this graph in the alt attribute. Luckily image has a longdesc attribute, you can link to another text or html file for more description. Here is an example:
    <img src=”/images/JanuarySales” alt=”January Sales per department” longdesc=”/reports/januarysales.htm”/>
  • If the images are disabled from the page, you should not lose any of the content from the page. Sometimes this happens because the image does not have an alt attribute, or the image is used as  a background decoration, and the front text color is same as background color and text disappears.

It is easy to test your page for this type of violation,  simply disable the images from your browser, and see if you still get the content :)

Tags:

Web Accessibility, Section 508 Guidelines

Powered by BlogEngine.NET 1.6.0.0
Original Design by Laptop Geek, Adapted by onesoft