In my last post I mentioned something nice about FireFox. In this post I’ll talk something not that nice about FireFox and the way we, more or less, worked around it.
A lot of people complain about Silverlight not working in Firefox. Including myself. Our DeepEarth page looks great in IE or Safari but in Firefox there is nothing to be seen at all. Not even an error message. There is quite a discussion on Silverlight and Firefox over here which branches in many directions. Thanks to Willem who spotted the one comment by Makkros which was the key to the solution.
The problem with Silverlight in Firefox has all to do with sizing. Take this snippet of the webpage
<div class="mapStyle">
<asp:Silverlight ID="TrackingMap" runat="server" Source="~/ClientBin/TrackingMap.xap" />
</div>
It’s a silverlight control enclosed in a div. As the control displays a map the best thing would be to claim as much space as available
<div class="mapStyle">
<asp:Silverlight ID="TrackingMap" runat="server" Width="100%" Height="90%" Source="~/ClientBin/TrackingMap.xap" />
</div>
This works in IE and Safari (and maybe more). When the browser window is resized the control takes up all space available with the div wrapping around.
Alas things work different in Firefox. Googling on Firefox DIV 100% results in many many hits. Firefox first sizes the DIV and then it’s up to the content to use it. Resulting in content sized 0 by 0. Which comes pretty close to invisible.
So you have to set the size of the control in absolute measures to see it. And resize it later on from script.
<div class="mapStyle">
<asp:Silverlight ID="TrackingMap" runat="server" Width="500px" Height="300px" Source="~/ClientBin/TrackingMap.xap" />
</div>
Alas this does not solve things at all. The initial size is OK, but resizing the control will not resize the wrapping DIV. Sizing the control over it’s initial size will crop a part, sizing it under it’s original size will result in an undesired border. It requires a full page refresh to get things into proportion again.
In the end I came up with this solution. Not that elegant, but it works. Any suggestions for something better are more than welcome.
In the page load of the code behind the control is given it’s initial size. A number of pixels for FF, a percentage for the rest.
protected void Page_Load(object sender, EventArgs e)
{
if (! IsPostBack)
{
if (Request.Browser.Browser.ToLower() == "firefox")
{
TrackingMap.Width = new Unit(mapWidth, UnitType.Pixel);
TrackingMap.Height = new Unit(mapHeight, UnitType.Pixel);
FireFoxWidth.Text = mapWidth.ToString();
FireFoxHeight.Text = mapHeight.ToString();
FireFoxSupport.Visible = true;
}
else
{
TrackingMap.Width = new Unit(100, UnitType.Percentage);
TrackingMap.Height = new Unit(88, UnitType.Percentage);
}
}
}
The number of pixels for the initial size is hard to guess. The browsercapabilties always suggest a 640*480 screen. Not that useful; I have to take arbitrary values. To house it I created two properties which store the values in the session
private const string ffMapWidth = "FFmapWidth";
private int mapWidth
{
get
{
var o = Context.Session[ffMapWidth];
if (o == null)
return 1024;
return int.Parse(o.ToString());
}
set
{
Context.Session[ffMapWidth] = value;
}
}
private const string ffMapHeight = "FFmapHeight";
private int mapHeight
{
get
{
var o = Context.Session[ffMapHeight];
if (o == null)
return 768;
return int.Parse(o.ToString());
}
set
{
Context.Session[ffMapHeight] = value;
}
}
It’s up to the user to pick a new size for the control, that’s what the FireFoxSupport control is for. That has two textboxes to enter the size and a button to perform the actual resize.
protected void resizeMap(object sender, EventArgs e)
{
try
{
mapWidth = int.Parse(FireFoxWidth.Text);
mapHeight = int.Parse(FireFoxHeight.Text);
Response.Redirect(Request.Url.ToString(), true);
}
catch
{
FireFoxWidth.Text = mapWidth.ToString();
FireFoxHeight.Text = mapHeight.ToString();
}
}
The new desired size is read from the textboxes and stored in the session using the properties. A complete rebuild of the page is enforced, the page load will now set the map to the desired size. And the div will wrap right because it’s a brand new page.
I don’t like this very much, but at least it does work. The only other working scenario I could imagine to circumvent the user taking care of the size is forcing a page refresh after a browser resize. Which stinks even more and will still leave the problem of finding out the available room. Which is a matter of chicken and egg.
I don’t want to get involved in any holy war on browsers or w3c but I really do believe Firefox does this completely wrong. Silverlight is not the only content suffering.