对 <base>标签的设计评论

 

今天又把上次改的东西重新改了一遍,因为相信世界是美好的。别人总是用比较好的思路来进行框架的设计。但事实上,理想是美好,现实是残酷的。

就像 <base> 标签的设置。

本来客户端的事情,应该交给客户端来处理。发送请求到服务器,是客户端的事情,而关于请求的地址,是客户端的事情。如果服务器不告诉客户端必须有某一个地址,那么客户端应该用他认为正确的地址与服务器进行通信。

如果,地址只是服务器的唯一标识,那么,由客户端或者服务器端处理都一样。但是,一个服务器确实可以处理多个不同的站点,称之为虚拟地址。于是,地址不在是唯一标识了。

而, 本来应该设置为定义整个站点的链接基础前缀,却没有遵循这个规则。 标签必须指明通信的地址,不能依靠客户端推断。只是近期到了 HTML 5 以后,才出现一些转折,支持相对路径(也就是客户端推断地址)。

实际上,这个也许就是当初设计的时候考虑不周的后果吧。

大概因为当时没考虑到,到底会有多少种地址存在。

现在想想,其实真正的地址大概有 3 种吧。因为地址的构成实际上是三部分,主机、端口、主机上地址。但是单凭主机和端口,实际上只能确定一个地址,就是根地址,这个地址不具有扩展性,而且是绝对地址的一个子集,所以,不在考虑之内;而地址实际上有 2 种,一种是相对路径绝对路径,实际上,是分别以当前路径和根路径为标准的两种地址表示方式;那么,而相对路径和绝对路径都必须以来主机和端口。但是如果没有给出主机端口的时候,客户端可以推断是当前的主机和端口,于是,实际上形成了 3 种地址方式。

  • 绝对资源地址:主机、端口、绝对地址
  • 绝对地址:只含有绝对地址(推断主机、端口为当前的主机、端口)
  • 相对地址:相对当前的地址(推断主机、端口为当前的主机、端口,并且,相对与当前的地址)

但是, 标签的设计却只考虑了第一种,而实际上,后两种也很常见。

或者 HTML 定制之初的 90 年代,当时简单的应用,就想到一个地址对应一个应用程序吧。但明显,Java 系的 ContextPath 已经突破了这个。现在大数据时代的到来,服务器平衡等早已经把服务器端做得越来越复杂,但是用户看起来却越来越简单……

浅谈 HTML 5

当然,我知道,聪明的你肯定也知道,HTML 5只是一个噱头而已,真正讨论的是移动互联网开发。

近几年来,在Web标准沉默了很多 年以及IE 6独占市场很多年以后,HTML 5神话地打破了这个局面,使得Web标准重新成为标准,并不受一家限制。这个主要归功于成功的开源HTML解释引擎Webkit(感谢Webkit、感谢 Apple,不过,其实真正该感谢的还是KDE,因为不是KHTML严格的GPL,Apple不知道会不会把拿KHTML来改造的Webkit开源 呢~)。不受平台限制,所以最终在几乎所有手机浏览器的内核都是Webkit(自带浏览器)。

不过,HTML 5真的还有很长的路要走。

近 几年来,HTML 5标签的变化主要集中在替代Flash的解决方案上,包括Canvas、Video以及Audio标签,至于其他标签,实际上可以通过CSS进行定制来模 拟,甚至很多标签基本没有所谓的式样,只是语义。但语义Web,我觉得是,HTML从创建之初就是用来格式化的,为什么语义?语义也应该是格式化上的语 义。

相比Flash,从设计之处就支持打算支持硬件加速的Canvas、Video以及Audio标签使页面运行更为流畅、自然。三个功能 单一化的标签,使得维护更容易。Video和Audio现在的问题就是如何维持浏览器之间的兼容性。而Canvas,其中一个很严重的缺点就是内容难以描 述,基于位图操作的Canvas对于图表,描述性自然是很差的,但愿SVG动画能够填补这个空白。Canvas的出现大概是为了游戏。但 JavaScript引擎的设计大多数是基于单线程的,对于游戏设计来说性能还是不好。

但HTML 5实际上伴随的变化,还在于CSS 3建立的互动模型。由于Webkit的流行,支持HTML 5就等于支持CSS 3。而CSS 3的动画、过渡、坐标变换等内容大大增强了HTML 5的表现力,实际上从原来基于函数的操作转换为基于模型(利用CSS 3的选择器来建模,然后用JavaScript调用模型之间的变化关系,其余操作由CSS动画过渡模块来解决)。这样,动画交互设计变得容易,静态的内容 真正动态化、互动化,革新了以往对Web纯静态平面设计的概念。但CSS 3现在面临的问题是,缺少对动画状态的描述。

说到CSS 3,不得不提的是硬件加速。相对于用JavaScript来实现的动画来说,CSS 3动画显然会更为流畅(浏览器的绘制的优化)。于是,很多动画框架从CSS 3中寻找解决方案,希望利用CSS 3来实现流畅的动画效果。但由于现阶段的CSS 3还缺少流程控制,还有基于CSS 3本身基于模型的设计。到底应不应该用CSS 3来达到除了互动以外的动画特效目的?还是浏览器应该定义一套支持硬件加速的基本API(WebGL?)来实现?

HTML的设计到现在来说还有一个很严重的问题——页面跳转间没有过渡效果。这个问题在jQuery Mobile中通过AJAX拉取页面然后动态插入DOM来解决,但这样实际上做了很多复杂的工作,代码兼容上也有问题。模拟的就绪事件还是不能和DOM就绪事件相比。

HTML 5还有一个很重要的组成部分就是JavaScript,这个逻辑与表现的桥梁。动态语言的优点或许不用我说了。而JavaScript有着和动态语言的通 病:难以进行静态语法分 析来进行上下文提示(这或许也是JavaScript没有神什么好用的IDE的原因之一)。那么使用这套语言的人必须十分清楚对象是什么,以及类有什么 API,否则,面对一个JS对象将无从下手。动态语言屏蔽了类型差异,为快速开发打下基础,但是模糊的语义在某些情况下又使得开发难度增加。

好了,先说到这里吧,有时难免情绪化,若有些错误,希望大家指出。也希望大家给出自己的意见。感谢收听~

 

新的一篇以及改进的主题

终于决定把博客迁到这里了。小玖似乎也不在百度空间了,而人人上压力巨大,大多数博客系统基本上不适合写代码……

昨天晚上把自定义 CSS 玩了一把。发现这里的自定义 CSS 挺好的,主题的 HTML 结构也很好(比百度空间的标准一点吧),附有多种主题作为基础选择。相对于以前的百度空间也算是一个进步。不过有些特效还是依赖 jQuery 等库才可以玩, CSS 3 的动画目前似乎只有gecko和webkit支持,opera也不支持(但我没有测试过,据W3schools.com的测试了解到的)。

主题主要修改部分:

  • 把 header 部分改为导航栏在上,然后用 position: fixed; 固定。考虑到 IE 可能不支持,我尝试删掉 position 属性定义,效果还可以,起码不会太乱。
    这样做的好处是看文章的时候总是可以见到导航栏,真正发挥导航的作用(呵呵,一家之言罢了)
  • header 上部分 float 的内容改用 position: absolute; 来替换。
  •  header 部分圆角边框和其他一些地方的圆角微调。
  • 改进了原来 #wrapper 控制的主内容区的排版方式。采用 margin-right 属性固定留空 #sidebar 区域,然后把 #sidebar 的 position 属性设置为 absolute ,当然,这样一来,为了排版,一些父元素的 position 也改成了 relative 。取消了原来的 float 和 width 固定页宽的排版方式。
    这个改进的好处是页面会随着屏幕的宽度而改变。尽可能不浪费横向空间的同时,也保留了版式的完整。但在小屏幕上,我承认这样的设计会有问题。但小屏幕的时候,浏览器应该不会过多地考虑 position 等定义吧(尽可能利用纵向空间)
  • 一些动画的改进。仅仅对Webkit和Gecko较新的内核上测试过。IE 肯定不支持的。看看 IE 10 吧。模拟了部分以往需要 jQuery 才能达到的动画效果。
  • 底部 footer 配合样式把宽度设为 100% 了。

基本上也就是这样了。有些细节可能没写出来,毕竟也很难完全写出来。参看我的 CSS 代码吧。:-)

#coldblue .inner {
  position: relative;
  margin: auto 20ex;
  width: auto;
}

#coldblue #search {
  position: fixed;
  top: 0;
  z-index: 100;
}

#coldblue #header {
  width: auto;
  margin: 50px 20ex 0;
  border-top-left-radius: 5px;
  border-top-right-radius: 5px;
}

#coldblue #header .inner {
  margin: 0 1ex;
}

#coldblue #header #navigation {
  float: none;
  top: auto;
  width: auto;
  position: absolute;
  right: 1ex;
  bottom: 1em;
}

#coldblue img[alt='Avatar'] {
  box-shadow: 0px 0px 10px #333;
}

#coldblue #head ~ h2, #coldblue #head ~ #chito_search {
  display: none;
}

#coldblue #chito_search ~ h2 {
  display: block;
}

#coldblue #chito_search + h2 {
  display: none;
}

@-moz-keyframes colorFadeAnimation {
  0% { color: white; }
  40% { color: yellow; }
  60% { color: yellow; }
  100% { color: white; }
}

@-webkit-keyframes colorFadeAnimation {
  0% { color: white; }
  40% { color: yellow; }
  60% { color: yellow; }
  100% { color: white; }
}

@keyframes colorFadeAnimation {
  0% { color: white; }
  40% { color: yellow; }
  60% { color: yellow; }
  100% { color: white; }
}

#coldblue #search a {
  color: white;
}

#coldblue #search .current_page_item a {
  text-shadow: 0px 0px 10px white;
  color: green;
}

#coldblue #search a:hover {
  -moz-animation:colorFadeAnimation 5s infinite;
  -moz-animation-play-state: running;
  -webkit-animation: colorFadeAnimation 5s infinite;
  -webkit-animation-play-state: running;
  animation: colorFadeAnimation 5s infinite;
  animation-play-state: running;
  color: yellow;
  text-shadow: 0px 0px 10px white;
}

#coldblue #wrapper {
  background-image: none;
  width: auto;
  margin: auto 20ex;
  position: relative;
  border-width: 0px;
}

#coldblue #wrapper #content {
  width: auto;
  margin-right: 270px;
  float: none;
}

#coldblue .post-title h3 {
  text-align: right;
}

#coldblue .post-p {
  padding: 0.3em;
  background-color: #aaa;
  border-radius: 0.2em;
}

@-moz-keyframes backgroundFade1 {
  0% { background-color: black; }
  50% { background-color: #888; }
  100% { background-color: black; }
}

@-webkit-keyframes backgroundFade1 {
  0% { background-color: black; }
  50% { background-color: #888; }
  100% { background-color: black; }
}

@keyframes backgroundFade1 {
  0% { background-color: black; }
  50% { background-color: #888; }
  100% { background-color: black; }
}

#coldblue .post-p a {
  padding: 0.1em;
  border-radius: 0.3em;
}

#coldblue .post-p a:hover {
  -moz-animation: backgroundFade1 4s infinite;
  -moz-animation-play-state: running;
  -webkit-animation: backgroundFade1 4s infinite;
  -webkit-animation-play-state: running;
  animation: backgroundFade1 4s infinite;
  animation-play-state: running;
  background-color: #888;
}

#coldblue #wrapper #sidebar {
  position: absolute;
  top: 0;
  right: 0;
  background-color: #ccc;
  border-bottom-left-radius: 15px;
}

#coldblue #footer {
  text-align: center;
  width: auto;
  margin: 0;
}

 

L.UI设计稿

本来应该写为文档的,不过,在下经验不多,还是用“稿”吧。

[pygame]有趣的游戏循环

不知道大家是怎么写pygame的绘制、时间循环的?像下面这样?

while True:
     for event in pygame.event.get():
         if event.type == QUIT: return
     #game loop...

很多教程,都很简单地使用了这样的循环……可惜的是这样跳出循环很容易导致很多问题,一是程序结构不好看(《DOM scripting with Javascript》的作者说的);二是,如果你的绘制代码是放在其他线程的话或者绘制代码时间滞后了,那个线程、那段代码可能会先抛出一个不明不白的“错误”才让你退出(至少对用户来说是这样)。

我以前也这样做,于是我的朋友问我,为什么你说你的程序做好了,但退出时却有一个令人费解的对话框出现啊?

我以前不太注重这些细节,因为对于我们来说,这些东西对使用时没有影响的。但对于用户来说,他们不知道我在程序里确切干了些什么,总会有一点害怕,害怕我把他的电脑搞坏了,或者怀疑自己的硬件有问题到维修店白跑一遍……呵呵,说得有点夸张了。

于是,我去pygame.org看看有没有人写出更好的循环结构呢?找到了一个……

while True:
     clock.tick(15)
     #game loop...
     for event in pygame.event.get():
         if event.type == pygame.locals.QUIT:
             raise SystemExit

这次把return改为raise SystemExit了,这样整个系统都会退出,这样基本上不会出现Windows那个什么提示错误的对话框了……然而,终端运行还是有问题,抛出了一个虚拟机退出而线程未完全退出的异常,不过对于Windows用户来说关系不大——他们大概不会在cmd下运行这个程序吧?但对于追求一个完美的结局,这样的结构显然还不够好……

while pygame.display.get_init():
     clock.tick(60)
     pygame.display.update()
     for event in pygame.event.get():
         if event.type == QUIT:
             t.running = False #退出线程
             pygame.quit() #退出pygame模块

这样就好了,循环根据pygame的display模块是否退出来判断是否继续执行,退出之前通知所有线程停止执行。(但对于线程执行时间滞后问题还是没有很好地解决)

其实都是具体问题具体分析,暂时还没有发现一个更好的方案了……

不知道大家有没有更好的循环写法呢?

 

 

 

[pygame]对象碰撞检测(二)

上一篇文章写了一个不完整的介绍,现在继续写它,当然,也是不完整的。

其实都是pygame 1.8.1更新的函数,由于没有中文资料,写写吧……虽然现在英文文档已经更新了。

以下所说的Sprite指的是继承了pygame.sprite.Sprite类的对象。

PyGame 1.8.1提供的新函数/类: 

pygame.sprite.collide_rect_ratio(ratio): return collided_callable
pygame.sprite.collide_circle(left, right): return bool
pygame.sprite.collide_circle_ratio( object ): return collided_callable

就写这三个吧。


pygame.sprite.collide_rect_ratio(ratio): return collided_callable

用于把Sprite的面积(rect属性,继承自pygame.Rect类)扩大ratio倍再进行比较,返回的是一个函数。它不会对Sprite的rect进行真实的扩大/缩小。

返回的函数可以作为

pygame.sprite.spritecollide(sprite, group, dokill, collided = None): return Sprite_list

中collided参数使用的(见上一篇文章)。但注意的是,这个不是一个函数,而是一个类,collided参数用的是这个类的实例,和上篇文章不同。
简化了自己编写自定义碰撞检测的麻烦,不过该函数仅仅对两个Sprite的rect扩大ratio倍再比较面积是否相交。

与之相似的是

pygame.sprite.collide_circle_ratio( ratio ): return collided_callable

不过,这个函数要求Sprite必须有radius属性(半径),根据半径扩大ratio倍。

这也是个类,定义与用法与pygame.sprite.collide_rect_ratio(ratio): return collided_callable相似。


pygame.sprite.collide_circle(left, right): return bool

left和right分别代表一个Sprite,事实上与Sprite所处的位置并没有要求(并不是规定left和right)。但这两个Sprite需要有额外的radius属性(表明半径)。

返回一个boolean(是否相交的布尔值)。这个函数也可以作为

pygame.sprite.spritecollide(sprite, group, dokill, collided = None): return Sprite_list

的collided参数使用。但和上两个类不同,这是一个函数,需要把这个函数的引用作为参数(例如:collided = pygame.sprite.collide_circle不需要括号)。


其实这些类或许在实际使用pygame模块没有什么用处,不过提供给我们一个对游戏中对象碰撞检测的参考~~~

 

 

[PyGame]碰撞检测

PyGame 1.7在pygame.sprite里为碰撞检测提供了三个函数:

 

spritecollide(sprite, group, dokill)

sprite - pygame.sprite.Sprite对象

group - pygame.sprite.Group对象(或其子类对象)

dokill - 是否杀死group中与sprite碰撞的sprite对象

返回包含所有group中与sprite相撞的sprite的列表(list)

 

groupcollide(groupa, groupb, dokilla, dokillb)

groupa - pygame.sprite.Group对象(或其子类对象)

groupb - pygame.sprite.Group对象(或其子类对象)

dokilla - 是否杀死groupa中与groupb中碰撞的sprite对象

dokillb - 是否杀死groupb中与groupa中碰撞的sprite对象

返回包含所有groupa中与groupb相撞的sprite的字典(dict)

 

spritecollideany(sprite, group)

和spritecollide(sprite, group, dokill)相似,但只是返回group中最第一个与sprite相碰撞的sprite。